Escalando com Reducer e Context
Reducers permitem consolidar a lógica de atualização de estado de um componente. Context permite passar informações profundamente para outros componentes. Você pode combinar reducers e context para gerenciar o estado de uma tela complexa.
Você aprenderá
- Como combinar um reducer com context
- Como evitar passar estado e dispatch através de props
- Como manter a lógica de context e estado em um arquivo separado
Combinando um reducer com context
Neste exemplo daintrodução aos reducers, o estado é gerenciado por um reducer. A função reducer contém toda a lógica de atualização de estado e é declarada no final deste arquivo:
Um reducer ajuda a manter os manipuladores de eventos curtos e concisos. No entanto, conforme seu aplicativo cresce, você pode encontrar outra dificuldade.Atualmente, o estadotaskse a funçãodispatchestão disponíveis apenas no componente de nível superiorTaskApp.Para permitir que outros componentes leiam a lista de tarefas ou a alterem, você precisa explicitamentepassar para baixoo estado atual e os manipuladores de eventos que o alteram como props.
Por exemplo,TaskApppassa uma lista de tarefas e os manipuladores de eventos paraTaskList:
E TaskListpassa os manipuladores de eventos paraTask:
Em um exemplo pequeno como este, isso funciona bem, mas se você tiver dezenas ou centenas de componentes no meio, passar todo o estado e as funções pode ser bastante frustrante!
É por isso que, como alternativa a passá-los através de props, você pode querer colocar tanto o estadotasksquanto a funçãodispatch em context.Dessa forma, qualquer componente abaixo deTaskAppna árvore pode ler as tarefas e despachar ações sem a repetitiva "prop drilling".
Veja como você pode combinar um reducer com context:
- Criaro contexto.
- Colocaro estado e a função dispatch no contexto.
- Usaro contexto em qualquer lugar da árvore.
Passo 1: Criar o contexto
O HookuseReducerretorna a lista atual detaskse a funçãodispatchque permite atualizá-las:
Para passá-los pela árvore, você irácriardois contextos separados:
TasksContextfornece a lista atual de tarefas.TasksDispatchContextfornece a função que permite aos componentes despachar ações.
Exporte-os de um arquivo separado para que possa importá-los posteriormente de outros arquivos:
Aqui, você está passandonullcomo o valor padrão para ambos os contextos. Os valores reais serão fornecidos pelo componenteTaskApp.
Passo 2: Colocar o estado e a função dispatch no contexto
Agora você pode importar ambos os contextos no seu componenteTaskApp. Pegue astaskse a funçãodispatchretornadas poruseReducer() e forneça-aspara toda a árvore abaixo:
Por enquanto, você passa a informação tanto via props quanto no contexto:
No próximo passo, você removerá a passagem de props.
Passo 3: Use o contexto em qualquer lugar da árvore
Agora você não precisa passar a lista de tarefas ou os manipuladores de eventos pela árvore:
Em vez disso, qualquer componente que precise da lista de tarefas pode lê-la doTasksContext:
Para atualizar a lista de tarefas, qualquer componente pode ler a funçãodispatchdo contexto e chamá-la:
O componenteTaskAppnão passa nenhum manipulador de eventos para baixo, e o componenteTaskListtambém não passa nenhum manipulador de eventos para o componenteTask.Cada componente lê o contexto de que precisa:
O estado ainda “vive” no componente de nível superiorTaskApp, gerenciado comuseReducer.Mas suas propriedadestasks e dispatchagora estão disponíveis para todos os componentes abaixo na árvore, importando e usando esses contextos.
Movendo toda a fiação para um único arquivo
Você não precisa fazer isso, mas poderia despoluir ainda mais os componentes movendo tanto o redutor quanto o contexto para um único arquivo. Atualmente,TasksContext.jscontém apenas duas declarações de contexto:
Este arquivo está prestes a ficar lotado! Você moverá o redutor para o mesmo arquivo. Em seguida, declarará um novo componenteTasksProviderno mesmo arquivo. Este componente unirá todas as peças:
- Ele gerenciará o estado com um redutor.
- Ele fornecerá ambos os contextos aos componentes abaixo.
- Elereceberá children como uma proppara que você possa passar JSX para ele.
Isso remove toda a complexidade e fiação do seu componenteTaskApp:
Você também pode exportar funções queusamo contexto deTasksContext.js:
Quando um componente precisa ler o contexto, ele pode fazer isso através dessas funções:
Isso não altera o comportamento de forma alguma, mas permite que você posteriormente separe esses contextos ainda mais ou adicione alguma lógica a essas funções.Agora toda a fiação de contexto e redutor está emTasksContext.js. Isso mantém os componentes limpos e organizados, focados no que exibem em vez de onde obtêm os dados:
Você pode pensar emTasksProvidercomo uma parte da tela que sabe como lidar com tarefas,useTaskscomo uma forma de lê-las euseTasksDispatchcomo uma forma de atualizá-las de qualquer componente abaixo na árvore.
Observação
Funções comouseTasks e useTasksDispatchsão chamadas deHooks Personalizados.Sua função é considerada um Hook personalizado se seu nome começar comuse. Isso permite que você use outros Hooks, comouseContext, dentro dela.
À medida que seu aplicativo cresce, você pode ter muitos pares de contexto e redutor como este. Esta é uma maneira poderosa de escalar seu aplicativo eelevar o estadosem muito trabalho sempre que quiser acessar os dados profundamente na árvore.
Recapitulação
- Você pode combinar um reducer com contexto para permitir que qualquer componente leia e atualize o estado acima dele.
- Para fornecer o estado e a função dispatch aos componentes abaixo:
- Crie dois contextos (um para o estado e outro para as funções dispatch).
- Forneça ambos os contextos a partir do componente que usa o reducer.
- Use qualquer um dos contextos a partir dos componentes que precisam lê-los.
- Você pode organizar ainda mais os componentes movendo toda a configuração para um único arquivo.
- Você pode exportar um componente como
TasksProviderque fornece o contexto. - Você também pode exportar Hooks personalizados como
useTaskseuseTasksDispatchpara lê-lo.
- Você pode exportar um componente como
- Você pode ter muitos pares de contexto-reducer como este em seu aplicativo.
