Primeiros passos com React Hooks — useReducer.
Nessa série de artigos vamos falar sobre os novos hooks disponibilizados na versão 16.8 do React.
1° Artigo: useState
2° Artigo: useEffect
Hoje o assunto é useReducer!
Introdução
Quem ainda não se perdeu nos “emaranhados” do Redux que atire a primeira pedra! Por isso entender o flow do Redux as vezes não é o suficiente, os apps tendem a crescer e perder seu padrão quando passam nas mãos de vários desenvolvedores.
UseReducer é uma forma mais limpa e menos verbosa de implementar um redutor para desacoplar a lógica de “ações” do seu componente.
Comparações
Resumidamente o flow do Redux em imagem:
Quando tomamos a decisão de implementar o flow do Redux nas nossas aplicações React, logo nos vem em mente toda aquela implementação de store/actions/reducers/combineReducers/middlewares/mapStateToProps/mapDispatchToProps, etc ….
Implementar toda essa “infraestrutura” faz sentido quando queremos descentralizar a forma de como as ações são executadas nos nossos componentes.
UseReducer é uma forma de implementar um redutor sem precisamos de toda a implementação que o Redux traz com ele.
UseReducer recebe 3 argumentos:
1° reducer do tipo (state, action) => newState.
2° initialArg, o state inicial para aquele redutor.
3° (opcional) uma função “init” que vai setar o state inicial para init(initialArg).
Exemplo:const [ state, dispatch ] = useReducer(reducer, initialArg, init);
UseReducer retorna um array com o state para aquele redutor e o dispatch (se você já usou Redux sabe como isso funciona).
Exemplo
Agora que já entendemos como useReducer funciona vamos voltar para nosso componente de Login e fazer um pequeno refactory nele.
Estado atual do nosso componente.
Olhando para nosso componente vamos imaginar que queremos descentralizar as ações do usuário para um redutor.
Em nosso redutor vamos separar em duas actions.
1° FETCHED_USER: Que ficará responsável por atualizar o state “user ” caso o usuário seja encontrado.
2° USER_LOGIN: Que será responsável pelo login do usuário.
Com isso, nosso redutor ficará assim.
Note que nosso redutor expõem duas constantes. O state inicial (initialUserState) e o próprio redutor (reducerUser).
O método postUserLogin é responsável por chamar o serviço (API) e fazer o login do usuário (aqui vamos focar no uso do redutor).
Agora com as ações criadas vamos implementar o redutor em nosso componente de Login.
Agora, vamos olhar as modificações que fizemos;
Line 5: Trocamos nosso useState que guardava os dados do usuário pela implementação do nosso redutor. Agora temos userState que guarda todas as informações do redutor do usuário e o dispatch responsável por despachar as ações.
Line 6: Estamos fazendo um destructuring do state do redutor retirando apenas as props que iremos usar.
Prop USER: guarda as informações do usuário recebidas do serviço.
Prop fetchedUser: guarda a informação, que a busca do usuário no serviço foi realizada com sucesso.
Line 13: Dentro do nosso efeito de renderização depois de receber o user caso seja encontrado vamos chamar o dispatch com a action ‘FETCHED_USER’ que atualizará o user.
Line 30: Dentro da nossa função handleSubmit vamos chamar o dispatch com action ‘USER_LOGIN’ que irá criar a autenticação do user.
Vantagens
Note que agora desacoplamos a lógica de ações do nosso componente, com isso, o componente pode ganhar nossas actions sem perder seu padrão. Essa abordagem te ajuda a deixa seu componente mais limpo e com pouco/nenhuma manipulação de estado.
Nem tudo são flores …
O bom uso de redutores vai te ajudar a deixar os componentes mais limpos, mais é importante entender que desacoplar ações pode deixa seu APP mais complexo, por isso, quando usar redutores a organização é fundamental para manter o padrão para novas implementações de redutores e actions.
Eu costumo dizer que quanto mais simples melhor, com uma boa organização useReducer vai te ajudar a ter componentes de fácil manutenção e entendimento.
Conclusão
Esse é um dos hooks que mais gosto. O principio de responsabilidade única é algo que corre na veia (e isso não é um particularidade do backend)!
UseReducer faz com que os componentes tenham apenas a responsabilidade de renderizar o que nós solicitamos, toda a parte de lógica de estado fica por conta do redutor de forma simples e desacoplada.
Aqui não se torna necessário todo o conhecimento no flow do Redux (apesar de muito valido), com isso a curva para implementar um redutor é quase zero.
Você pode combinar o uso de useReducer com useContext para ter state e dispatch globais, vamos falar mais disso no próximo artigo.
No próximo artigo da serie vamos falar um pouco sobre useContext.
Referências
- How to useReducer in React?
https://www.robinwieruch.de/react-usereducer-hook/ - Hooks-UseReducer
https://reactjs.org/docs/hooks-reference.html#usereducer