v19.2Latest

Escalando con Reducer y Context

Los reducers te permiten consolidar la lógica de actualización del estado de un componente. Context te permite pasar información profundamente a otros componentes. Puedes combinar reducers y context para gestionar el estado de una pantalla compleja.

Aprenderás
  • Cómo combinar un reducer con context
  • Cómo evitar pasar estado y dispatch a través de props
  • Cómo mantener la lógica de context y estado en un archivo separado

Combinando un reducer con context

En este ejemplo dela introducción a los reducers, el estado es gestionado por un reducer. La función reducer contiene toda la lógica de actualización del estado y se declara al final de este archivo:

Un reducer ayuda a mantener los controladores de eventos cortos y concisos. Sin embargo, a medida que tu aplicación crece, podrías encontrarte con otra dificultad.Actualmente, el estadotasksy la funcióndispatchsolo están disponibles en el componente de nivel superiorTaskApp.Para permitir que otros componentes lean la lista de tareas o la modifiquen, tienes quepasar explícitamenteel estado actual y los controladores de eventos que lo cambian como props.

Por ejemplo,TaskApppasa una lista de tareas y los controladores de eventos aTaskList:

Y TaskListpasa los controladores de eventos aTask:

En un ejemplo pequeño como este, funciona bien, pero si tienes decenas o cientos de componentes en el medio, pasar todo el estado y las funciones puede ser bastante frustrante.

Por eso, como alternativa a pasarlos a través de props, es posible que desees colocar tanto el estadotaskscomo la funcióndispatch en un contexto.De esta manera, cualquier componente debajo deTaskAppen el árbol puede leer las tareas y despachar acciones sin el repetitivo "prop drilling".

Así es como puedes combinar un reducer con contexto:

  1. Crearel contexto.
  2. Colocarel estado y la función dispatch en el contexto.
  3. Usarel contexto en cualquier parte del árbol.

Paso 1: Crear el contexto

El HookuseReducerdevuelve la lista actual detasksy la funcióndispatchque te permite actualizarlas:

Para pasarlos hacia abajo en el árbol,crearásdos contextos separados:

  • TasksContextproporciona la lista actual de tareas.
  • TasksDispatchContextproporciona la función que permite a los componentes despachar acciones.

Expórtalos desde un archivo separado para que luego puedas importarlos desde otros archivos:

Aquí, estás pasandonullcomo valor predeterminado a ambos contextos. Los valores reales serán proporcionados por el componenteTaskApp.

Paso 2: Colocar el estado y la función dispatch en el contexto

Ahora puedes importar ambos contextos en tu componenteTaskApp. Toma lastasksy la funcióndispatchdevueltas poruseReducer() y proporciónalasa todo el árbol que está debajo:

Por ahora, pasas la información tanto mediante props como en el contexto:

En el siguiente paso, eliminarás el paso de props.

Paso 3: Usa el contexto en cualquier parte del árbol

Ahora no necesitas pasar la lista de tareas o los manejadores de eventos hacia abajo en el árbol:

En su lugar, cualquier componente que necesite la lista de tareas puede leerla desde elTasksContext:

Para actualizar la lista de tareas, cualquier componente puede leer la funcióndispatchdel contexto y llamarla:

El componenteTaskAppno pasa ningún controlador de eventos hacia abajo, y el componenteTaskListtampoco pasa ningún controlador de eventos al componenteTask.Cada componente lee el contexto que necesita:

El estado aún “vive” en el componente de nivel superiorTaskApp, gestionado conuseReducer.Pero sustasks y dispatchahora están disponibles para cada componente inferior en el árbol importando y usando estos contextos.

Mover todo el cableado a un solo archivo

No tienes que hacer esto, pero podrías despejar aún más los componentes moviendo tanto el reducer como el contexto a un solo archivo. Actualmente,TasksContext.jscontiene solo dos declaraciones de contexto:

¡Este archivo está a punto de llenarse! Moverás el reducer a ese mismo archivo. Luego declararás un nuevo componenteTasksProvideren el mismo archivo. Este componente unirá todas las piezas:

  1. Gestionará el estado con un reducer.
  2. Proporcionará ambos contextos a los componentes inferiores.
  3. Tomaráchildren como proppara que puedas pasarle JSX.

Esto elimina toda la complejidad y el cableado de tu componenteTaskApp:

También puedes exportar funciones queutilicenel contexto desdeTasksContext.js:

Cuando un componente necesita leer el contexto, puede hacerlo a través de estas funciones:

Esto no cambia el comportamiento de ninguna manera, pero te permite luego dividir estos contextos más o añadir lógica a estas funciones.Ahora todo el cableado del contexto y el reducer está enTasksContext.js. Esto mantiene los componentes limpios y ordenados, enfocados en lo que muestran en lugar de en dónde obtienen los datos:

Puedes pensar enTasksProvidercomo una parte de la pantalla que sabe cómo manejar tareas,useTaskscomo una forma de leerlas, yuseTasksDispatchcomo una forma de actualizarlas desde cualquier componente más abajo en el árbol.

Nota

Funciones comouseTasks y useTasksDispatchse denominanHooks personalizados.Tu función se considera un Hook personalizado si su nombre comienza conuse. Esto te permite usar otros Hooks, comouseContext, dentro de ella.

A medida que tu aplicación crece, puedes tener muchos pares de contexto-reductor como este. Esta es una forma poderosa de escalar tu aplicación yelevar el estadosin demasiado trabajo cada vez que quieras acceder a los datos en lo profundo del árbol.

Recapitulación

  • Puedes combinar un reducer con el contexto para permitir que cualquier componente lea y actualice el estado por encima de él.
  • Para proporcionar el estado y la función dispatch a los componentes inferiores:
    1. Crea dos contextos (uno para el estado y otro para las funciones dispatch).
    2. Proporciona ambos contextos desde el componente que utiliza el reducer.
    3. Utiliza cualquiera de los contextos desde los componentes que necesiten leerlos.
  • Puedes despejar aún más los componentes moviendo todo el cableado a un solo archivo.
    • Puedes exportar un componente comoTasksProviderque proporcione el contexto.
    • También puedes exportar Hooks personalizados comouseTasks y useTasksDispatchpara leerlo.
  • Puedes tener muchos pares contexto-reducer como este en tu aplicación.