Entendendo useState e useReducer
Antoniel Magalhães
Posted on February 1, 2021
Introdução
O estado em uma aplicação react é um faz parte dos conceitos fundamentais da biblioteca, desde a adoção dos hooks na versão 16.8 temos dois hooks que tem a função de lidar com estados, o useState e o useReducer. Nesse post eu vou tentar dar uma breve explicação sobre cada um dos hooks e suas particularidades;
useState
De acordo com @types/react o hook useState possui a seguinte tipagem:
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
-
O useState recebe um parâmetro, o initialState
- Esse parâmetro pode ser um valor do tipo S ou uma função que retorna o tipo S, que é um
tipo genérico
ou seja, assume o tipo do seu estado, podendo ser um numero, string, ou um objeto qualquer.
- Esse parâmetro pode ser um valor do tipo S ou uma função que retorna o tipo S, que é um
-
O useState retorna uma array de duas posições
- S se refere ao estado atual
- Dispatch> é a função que vai atualizar aquele componente, o dispatch pode receber o valor que o estado vai ser atualizado ou um callback do tipo
((prevState: S) => S);
recebendo o estado anterior e retornando o estado atual.
useReducer
Ainda de acordo com @types/react o hook useReducer possui a seguinte tipagem,A estrutura básica do useReducer é uma função que recebe entre 2 e 3 parâmetros e retorna um array de duas posições:
function useReducer<R extends Reducer<any, any>, I>(
reducer: R,
initializerArg: I,
initializer: (arg: I) => ReducerState<R>
): [ReducerState<R>, Dispatch<ReducerAction<R>>];
)
- Os parâmetros do useReducer:
Reducer é um callback com a seguinte estrutura:
(prevState: S, action: A) => S;
, esse callback é o responsável por atualizar o estado, seria o equivalente ao SetStateAction do useState, porém com suas particularidades, a exemplo o parâmetro do callback, o action, nele é possível definir o tipo da ação, passar dados através do payload, o reducer deve ficar mais claro durante os exemplos.O initializerArg assim como initialState do useState é o parâmetro que vai receber o estado inicial do estado.
O
initializer
, esse recebe uma função responsável por modificar o initializeArg durante a montagem do componente modificando o estado inicial do reducer.
- O useReducer retorna um array com 2 parâmetros:
[ReducerState<R>, Dispatch<ReducerAction<R>>]
- O primeiro parâmetro é o State do useReducer
- O segundo parâmetro é a função que vai chamar o reducer (1º parâmetro do useReducer), recebendo parâmetro action, onde no retorno do reducer o state é atualizado.
Exemplos
partindo do caso de uso que o nosso estado é uma lista de jogadores, como podemos modificar essa lista utilizando o useState e o useReducer.
useState
/* No caso do useState se quisermos alterar esse estado em um componente abaixo podemos passar o setPlayer como prop. e montar o callback no componente abaixo, ou montar o addPlayer e passa-lo como prop. */
const [players, setPlayers] = useState(initialState);
const addPlayer = (newPlayer) => {
setPlayers([...players, newPlayer])
}
// Como o setPlayers vai ser chamado 👇
addPlayers('Ronaldo')
useReducer
/* Com o useReducer uma vez que defnimos a função reducer e suas ações passamos simplesmente o dispatch para baixo na arvore de componentes e cada componente chama a sua respectiva ação */
const reducer = (state, action) => {
switch (action.type) {
case "addPlayer": {
const newState = [...state, action.payload];
return newState;
}
default:
}
}
const [players, dispatch] = useReducer(reducer, initialArg);
// Como o reducer vai ser chamado 👇
dispatch({ type : addPlayer, payload : "Ronaldo" })
Os dois códigos acima fazer a exatamente a mesma coisa, o useReducer parece muito mais verboso e compelxo que o useState, quais suas vantagens ? imagine uma situação que muitos outros métodos, adicionar, remover, atualizar... e ainda com outros estados como estado de loading, error entre outros. Como fariamos essas outras funções acessíveis para os componentes que a consomem ? criariamos uma nova prop para cada função, até setia possível mas imagina o caos que não seri esse componente, o useReducer aparece nesses casos onde você precisa lidar com muitos métodos e estados de um componente, a função reducer poderia ficar em um arquivo separado aumentando a qualidade e legibilidade do código, você saberia exatamente em qual tipo de action modificar, e ao invés de passar cada método com uma nova prop você pode passar só o dispatch e cada componente chama o tipo de ação que precisar.
Quando você precisa lidar com apenas um estado, é mais simples conveniente utilizar o useState ao invés do use Reducer apenas um estado para
References
Posted on February 1, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.