Redux: Seu useSelector hook mais perfomático.
Tags: react, reactnative, javascript, performance
Published: 2023-01-06 15:16:39

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:**

```react
/**
 * ❌ 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
}));
```

**Faça:**

```react
/**
 * ✅ 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);
```
### useSelector: retornando um objeto, mas você precisa somente de algumas propriedades desse objeto:

**Evite:**

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

**Faça:**

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

### 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:**

```react
/**
 * ❌ 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)
  );
}
```

**Faça:**

```react
/**
 * ❌ 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)
```

### 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.

```react
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;
}
```

#### 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://react-redux.js.org/api/hooks)

[https://redux.js.org/style-guide/#keep-state-minimal-and-derive-additional-values](https://redux.js.org/style-guide/#call-useselector-multiple-times-in-function-components)

[https://redux.js.org/usage/deriving-data-selectors](https://redux.js.org/usage/deriving-data-selectors)