DEV Community

Cover image for Redux: Seu useSelector hook mais perfomático.
Clayton Santos
Clayton Santos

Posted on

Redux: Seu useSelector hook mais perfomático.

Vamos ver alguns padrões comuns e como evitá-los fará seu código mais perfomático. Vamos explorar isso abaixo, mas antes alguns pontos importantes:

O hook useSelector permite extrair/selecionar dados do Redux.

O selector pode retornar qualquer valor como resultado, não apenas um objeto.

Quando uma action é disparada, useSelector() comparará o valor retornado anteriormente e o valor atual retornado. Se eles forem diferentes, o. componente será forçado a re-renderizar. Se eles forem iguais, o componente não re-renderizará.

Vamos lá:

UseSelector: retornando sempre um novo objeto e desestruturando.

Esse equívoco geralmente ocorre, pois achamos que chamar vários useSelectors é ruim, e isso não é verdade. Você pode e deve chamar vários useSelectors se necessário.

Evite:

/**
 * ❌ Atenção: sempre forçará seu componente a re-renderizar e será preciso usar
 * shalowEqual desnecessariamente
 */
const { name, token } = useSelector((state) => ({
  name: state.user.name,
  token: state.auth.token
}));
Enter fullscreen mode Exit fullscreen mode

Faça:

/**
 * ✅ Bom: somente forçará um render se e somente se o name ou token mudar.
 */
const name = useSelector((state) => state.user.name);
const token = useSelector((state) => state.auth.token);
Enter fullscreen mode Exit fullscreen mode

useSelector: retornando um objeto, mas você precisa somente de algumas propriedades desse objeto:

Evite:

/**
 * ❌ Atenção:
 * Força um re-render sempre que o objeto user mudar
 */
const user = useSelector((state) => state.user);
const { name, website } = user;
Enter fullscreen mode Exit fullscreen mode

Faça:

/**
 * ✅ Bom:
 * re-renderiza somente se name ou website forem diferentes
 */
const name = useSelector((state) => state.user.name);
const website = useSelector((state) => state.user.website);
Enter fullscreen mode Exit fullscreen mode

useSelector: usando Array.map, Array.filter etc. no seu selector.

Desde que esses métodos sempre retornam objetos diferentes, isso fará o useSelector forçar seu componente a sempre re-renderizar.

Evite:

/**
 * ❌ Atenção:
 * Renderizará sempre, pois o selector sempre retorna um novo objeto;
 * map, filter sempre retornam novo objeto.
 */
 const hobbies = useSelector((state) =>
    state.user.hobbies.filter((hobbie) => hobbie)
  );
}
Enter fullscreen mode Exit fullscreen mode

Faça:

/**
 * ❌ Melhor:
 * Renderizará sempre, pois o selector sempre retorna um novo objeto;
 * map, filter sempre retornam novo objeto.
 */
 const hobbies = useSelector((state) => state.user.hobbies,
   shalowEqual);
 }

const filteredHobbies = hobbies.filter((hobbie) => hobbie)
Enter fullscreen mode Exit fullscreen mode

Extra tip: hooks customizados

Desde que seus hooks encapsulam lógicas, é importante prestar atenção ao seus states internos. Se um state interno de um hook customizado mudar, este hook forçará um re-render no componente que o usa.

function Blog(){
/**
 * ❗️ Se o state de useBlogName mudar, Blog re-renderizará.
 */
  const blogName = useBlogName();
  //outros códigos aqui
}

function useBlogName() {
/**
 *  ✅ Bom: está otimizado
 */
  const name = useSelector((state) => state.blog.name);
  return name;
}
Enter fullscreen mode Exit fullscreen mode

Recapitulando:

Quanto mais específico seu seletor, melhor!
Isso evitará renders desnecessários nos seus componentes e os fará mais performáticos e resilientes a bugs.

Referências:

https://react-redux.js.org/api/hooks

https://redux.js.org/style-guide/#keep-state-minimal-and-derive-additional-values

https://redux.js.org/usage/deriving-data-selectors

Top comments (0)