v19.2Latest

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:

  1. Criaro contexto.
  2. Colocaro estado e a função dispatch no contexto.
  3. 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:

  1. Ele gerenciará o estado com um redutor.
  2. Ele fornecerá ambos os contextos aos componentes abaixo.
  3. 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:
    1. Crie dois contextos (um para o estado e outro para as funções dispatch).
    2. Forneça ambos os contextos a partir do componente que usa o reducer.
    3. 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 comoTasksProviderque fornece o contexto.
    • Você também pode exportar Hooks personalizados comouseTasks e useTasksDispatchpara lê-lo.
  • Você pode ter muitos pares de contexto-reducer como este em seu aplicativo.