Redux: Pregunta: ¿Cómo elegir entre la tienda de Redux y el estado de React?

Creado en 27 ene. 2016  ·  26Comentarios  ·  Fuente: reduxjs/redux

question

Comentario más útil

Use React para un estado efímero que no le importa a la aplicación a nivel mundial y que no mute de manera compleja. Por ejemplo, un conmutador en algún elemento de la interfaz de usuario, un estado de entrada de formulario. Use Redux para el estado que importa a nivel mundial o está mutado de manera compleja Por ejemplo, usuarios almacenados en caché o un borrador de publicación.

A veces querrás pasar del estado de Redux al estado de React (cuando almacenar algo en Redux se vuelve incómodo) o al revés (cuando más componentes necesitan tener acceso a algún estado que solía ser local).

La regla general es: haz lo que sea menos incómodo.

Todos 26 comentarios

Use React para un estado efímero que no le importa a la aplicación a nivel mundial y que no mute de manera compleja. Por ejemplo, un conmutador en algún elemento de la interfaz de usuario, un estado de entrada de formulario. Use Redux para el estado que importa a nivel mundial o está mutado de manera compleja Por ejemplo, usuarios almacenados en caché o un borrador de publicación.

A veces querrás pasar del estado de Redux al estado de React (cuando almacenar algo en Redux se vuelve incómodo) o al revés (cuando más componentes necesitan tener acceso a algún estado que solía ser local).

La regla general es: haz lo que sea menos incómodo.

Para los datos obtenidos a través de solicitudes de red, siempre use las tiendas para admitir la representación del lado del servidor (si cree que ese es el objetivo final), o no podrá rehidratarse.

¿Para que esos estados sean escuchados por dos o más contenedores, también debería estar en las tiendas?

Estoy de acuerdo con @gaeron sobre la distinción entre efímero y persistente. Pero en realidad pienso en esto en tres categorías . Uno es el estado de la estado de la estado de enrutamiento . Utilizo el término "enrutamiento" porque es familiar para la gente, pero lo abstraigo a un estado de "selección de vista", ya que creo que abarca mejor el escritorio, la web y los dispositivos móviles.

Ahora podría argumentar que este es el estado de la interfaz de usuario porque está decidiendo lo que ven las personas (muy parecido al estado de las pestañas, por ejemplo). Pero veo dos distinciones. La primera es que el estado se serializa (es decir, como una URL) y se envía a otras personas. Por lo tanto, las cosas deberían ir en el estado de ruta si desea que las personas puedan realizar un "enlace profundo" directamente a ese estado de IU particular . La segunda es que, en muchos casos, el estado de la ruta inicial o un cambio en la ruta desencadena un cambio en el estado de la aplicación (es decir, cargar los datos que se van a ver). Por supuesto, las acciones en la interfaz de usuario hacen lo mismo. Pero la distinción que hago es que puede (y debe) tener el estado de la ruta sin ninguna vista o representación precisamente para probar la "lógica de la aplicación" en torno a los cambios en el estado de la ruta. Y es porque la vista y la representación no necesitan estar involucradas, lo que lo convierte en parte en un estado de aplicación, en mi humilde opinión.

¿Cómo se relaciona esto con la cuestión de Redux vs. React para la gestión estatal? El estado de la aplicación es el dominio de Redux y el estado de la interfaz de usuario es el dominio de React. Pero el estado de enrutamiento debería (en mi opinión) ser administrado por Redux a pesar de que puede verse como un estado de interfaz de usuario (consulte los enlaces integrados para obtener más información sobre por qué creo eso).

Para ser claros, el comentario de @gaearon sobre las cosas que se mueven todavía se aplica. Pero me parece útil distinguir estos diferentes casos.

El estado de la aplicación es el dominio de Redux y el estado de la interfaz de usuario es el dominio de React.

Tenga en cuenta que no reclamo esto. Creo que está bien mantener el estado de la aplicación en React y el estado de la interfaz de usuario en Redux. No creo que deban estar separados por dominios.

De la forma en que lo pienso, si crea una aplicación con Redux, adopte el árbol de estado único. Ponga el estado de la interfaz de usuario allí también. Sin embargo, si se vuelve tedioso y frustrante , no tenga miedo de poner estado en los componentes. Mi punto es que use un árbol de estado único a menos que sea incómodo, y solo haga esto cuando le simplifique las cosas en lugar de complicarlas. Esa es la única pauta.

Primero, ciertamente no quise poner palabras en la boca de

En segundo lugar, estoy completamente de acuerdo con @gaearon. También creo firmemente en un enfoque de árbol de estado único. Cuando hablé sobre el estado de la interfaz de usuario, tenía en mente cosas realmente menores (como cuál es la pestaña actual seleccionada) donde podría no ser realmente tan relevante para el estado de la aplicación (exactamente se ha discutido @gaearon ).

Así que déjame aclarar mi posición. Estoy de acuerdo en que casi todo debería estar en Redux , incluido el estado de la ruta (como lo hice en mi implementación de TodoMVC con Redux y TypeScript . Mencioné específicamente el estado de la ruta y lo distinguí porque creo (y puedes verlo en ese TodoMVC implementación) que definitivamente pertenece a Redux (y no debería estar conectado en absoluto al renderizado) y definitivamente no es un "estado de IU".

Para los componentes de React, rara vez uso el estado. Prefiero usar accesorios tanto para obtener información sobre qué renderizar como para obtener cierres que puedo invocar para activar cambios externos a mi componente. Hay algunas circunstancias poco frecuentes en las que introduzco el estado en los componentes solo para hacer la vida más fácil, pero trato de evitarlo. Espero que esto aclare las cosas.

Creo que esta pregunta es muy subjetiva y complicada, así que hoy tomé una decisión difícil con mi equipo, no te molestes:

  • para el contenedor no reutilizable, que tiene conexión a Redux, simplemente coloque todo en la tienda de Redux, incluso un estado de interfaz de usuario pequeño como si un modal estuviera abierto, no use this.setState más.
  • para el componente reutilizable, que no tiene nada que ver con Redux, use el estado React.

Y ahora estamos implementando algunos ayudantes para que sea menos tedioso administrar el pequeño estado de la interfaz de usuario.

@gaearon @ lionng429 @xogeny ¿ Algún inconveniente que pueda pensar de este enfoque?

@inetfuture Tiendo a ser un poco miserable sobre el estado de la aplicación (redux) porque estoy usando TypeScript y defino un tipo para el estado de mi aplicación hasta el final. Dicho esto, me involucré al desarrollar bibliotecas de componentes para separar toda la manipulación del estado de la representación (consulte los enlaces en los comentarios anteriores para obtener más detalles). Esto significa que incluso para los componentes generales que no son triviales, externalizo completamente el estado. Generalmente paso todo a través de accesorios (tanto estados como cierres para manipular el estado). De esa manera, puedo conectarlo fácilmente al estado de mi aplicación. Parte de esto es, sin duda, un artefacto de usar TypeScript y no poder usar solo combineReducers y connect para conectar cosas (y preservar las restricciones de tipo al menos). Así que probablemente este no sea un punto de vista representativo. Pero diré que por qué dices "solo pon todo en la tienda Redux", me preocuparía que termines con un fregadero de cocina de estado. Creo que el hecho de que mi uso de TypeScript signifique que se necesita algo de esfuerzo para expandir el estado de la aplicación no es necesariamente algo malo porque me obliga a decidir "¿realmente necesito esto?" en lugar de dejar que las cosas se acumulen.

Como idea alternativa: el estado del componente local puede ser útil para entradas controladas que necesitan un tiempo de actualización rápido, así como para reducir la cantidad de acciones reales activadas. En mi prototipo actual, armé un HOC de edición de formularios que recibe el elemento actual que se está editando como accesorio. También maneja eventos de cambio de entrada de formulario guardando el campo cambiado en su estado, luego llamando a un creador de acción sin rebotes "EDIT_ITEM_ATTRIBUTE" con los cambios WIP locales combinados. El resultado es que los campos del formulario se actualizan de inmediato, porque solo el formulario en sí se vuelve a renderizar y se activan muchas menos acciones (por ejemplo, si mantuviera presionada 'A' durante unos segundos, solo el valor 'AAAAAAAAAAAA' enviarse como una acción en lugar de 'A', 'AA', etc.).

Tengo el HOC como una esencia en https://gist.github.com/markerikson/554cab15d83fd994dfab , si a alguien le importa.

De todos modos, el punto es que el estado del componente y el estado de la tienda tienen sus usos; solo debe considerar su caso de uso real.

En cuanto a los componentes reutilizables, si son lo suficientemente grandes y complejos, sería bastante a prueba de futuro tener su estado en Redux, principalmente para la trazabilidad y la reproducción para las pruebas. Pero aún existen algunas dudas sobre cómo se debe diseñar exactamente esta reutilización de código (componentes más acciones más reductores).

En nuestras aplicaciones, resolvimos este problema con un estilo similar al de una conexión. https://github.com/Babo-Ltd/redux-state

Rara vez me resultaba incómodo almacenar estados en Redux. Me gusta la potencia que proporciona, que en el futuro puedo hacer que interactúe con algún otro componente si lo necesito.

Lo único que me viene a la mente donde sería incómodo es manejar el estado de los elementos del formulario, porque puede haber muchos de ellos. En ese caso, uso una biblioteca como redux-form .

Mi punto es que use un árbol de estado único a menos que sea incómodo, y solo haga esto cuando le simplifique las cosas en lugar de complicarlas. Esa es la única pauta

@gaearon, ¿le gustaría compartir sus experiencias sobre cómo decidir cuándo o cómo se considera que es _incómodo_? por ejemplo, ¿puede dar algunos escenarios / ejemplos típicos que cree que son lo suficientemente incómodos si se colocan en el estado de la aplicación atom? ¡gracias por adelantado!

@idavollen les puedo dar un par:

  • un estado de apertura / cierre desplegable, de lo contrario, tendría que realizar un seguimiento de todos los componentes del menú desplegable en su tienda
  • cuando está eliminando un cambio de <input> , puede usar el estado para actualizar el valor instantáneamente (y no está arriesgando otros componentes para volver a renderizar innecesariamente) y actualizar la tienda de una manera sin rebotes

Básicamente, debería usarlo para el estado que no afecta a otros componentes.

Tengo una tercera situación a considerar, por ejemplo, tengo un formulario (un componente de contenedor de reacción que tiene un cálculo costoso en el método de renderizado) que consta de muchas líneas con una casilla de verificación precedida y un botón de envío. Cuando se hace clic en el botón enviar, el formulario debe enviar las líneas cuyas casillas de verificación están marcadas, lo que significa estados transitorios de la casilla de verificación individual antes de enviar el formulario cuando el usuario cambia, no es importante y no debe tratarse como un estado de componente y alternar la casilla de verificación no debe causar render () para ser llamado.

Por el momento, no pondría estados de casilla de verificación en el átomo de estado de la aplicación, ni en el estado del componente local, es decir, el componente de reacción de formulario para evitar llamadas innecesarias de render () mientras se alterna la casilla de verificación, por el contrario, un Se prefiere la variable de instancia para mantener las casillas de verificación marcadas, sin embargo, es contra el patrón de reacción.

Me pregunto cuál es el mejor enfoque para administrar estos estados de casillas de verificación en este caso.

@idavollen, ¿esas casillas de verificación no están

¿Qué tan rápido es Redux en comparación con el estado de los componentes? ¿Debo confiar en Redux para los accesorios de UI que son realmente sensibles en términos de tiempo entre el evento real y el proceso de renderizado? Tengo una situación complicada en la que usar el estado de los componentes requeriría mucha comunicación no tan directa. Cualquier ayuda en este asunto será muy apreciada.

@tiberiumaxim En mi experiencia (desarrollo aplicaciones en react y redux que se ejecutan en dispositivos de baja potencia como Smart TV). En la mayoría de los casos, la actualización del estado del componente será más eficaz, solo porque la diferencia que debe ocurrir está en un conjunto de datos más pequeño y no es necesario que ocurran envíos. En los casos en los que solo el componente o los niños necesitan acceso a ese estado, sería mejor seguir con el estado del componente local y este suele ser el caso con el estado relacionado con la interfaz de usuario, si, sin embargo, necesita conservar esos datos en la tienda redux en algún momento: es posible que deba usar una combinación de estado local (componente) vs global (redux) y asegurarse de conservar esos datos en la tienda redux en el momento correcto, es decir, cuando un usuario navega fuera de la página, o algo por el estilo. Tal vez si pudiera arrojar algo más de luz sobre su caso específico, podría brindarle información más detallada.

Depende de usted decidir qué estado va en Redux y qué permanece local en un componente. Es posible que desee leer http://redux.js.org/docs/faq/OrganizingState.html#organizing -state-only-redux-state y http://redux.js.org/docs/faq/Performance. html # performance -scaling para obtener información relacionada.

@deowk gracias por compartir su conocimiento sobre el tema del rendimiento, pensé lo mismo pero necesitaba confirmación.
Además, @markerikson , gracias por los enlaces, los echaré un vistazo una vez más.

No estoy seguro si alguien lo mencionó explícitamente, pero el estado del componente local también puede ser administrado por Redux. Puede crear una tienda directamente en el constructor de su componente. Esta tienda local contendría el estado de este componente y manejaría las acciones relacionadas con este componente (y sus hijos pasando la función dispatch de esta tienda o las devoluciones de llamada que llaman a esa función dispatch ) .

Esta arquitectura se puede implementar manualmente o usar alguna biblioteca como redux-fractal, redux-ui, etc.

O, como ha señalado Dan, ¡incluso puede implementar un enfoque de estilo reductor para actualizar el estado de un componente también! Ver https://twitter.com/dan_abramov/status/736310245945933824

Quiero saber dónde almacenar el estado de la interfaz de usuario, como el indicador de actividad y la apertura o cierre modal. ¿El uso de setState causa problemas en las pruebas unitarias de los componentes react?

@ akshay2604 : de nuevo, eso depende de ti. Vea los enlaces que publiqué en comentarios anteriores en este hilo. Definitivamente puede usar setState mientras prueba componentes, especialmente si está usando la biblioteca Enzyme para ayudar a probarlos.

Déjame compartir mis pensamientos.

Clasifico el estado en 3 categorías amplias de acuerdo con su relación con la entrada / salida de la aplicación:

  • "caché": un estado que es un espejo de datos persistentes. Ejemplo:
{ "todos": [{ id: 1, title: "title" }, { id: 2, title: "title" }] }
  • "cambios": un estado que describe los cambios pendientes en los datos persistentes. Ejemplo:
{ "changeTodo": { title: "title", action: "add", done: false },
{ id: 1, title: "changed title", action: "modify", done: true }, { id: 2, action: "delete" } }
  • "vista": un estado que transmite opciones de vista como filtrado actual, clasificación, etc. Ejemplo:
{ "displayOptions": { searchTerm: "title", sort: ["title", "desc"], filter: "done=false" } }

No mezclas cache con changes , no mezclas cache con view , no mezclas view con changes .

Por supuesto, debe fusionar estos de alguna manera para mostrarlo en un solo componente de reacción. Para que su objeto "fusionado" se convierta en:

{ "todos": [{id: undefined, title: "title", done: false }, { id: 1, title: "changed title" }] }

Pero eso no es un estado, es el resultado de la lógica de su
Puede almacenar en caché este estado combinado en selectores, puede almacenarlo en la tienda, puede almacenarlo en componentes, pero no es un "estado", no es importante, puede volver a aplicar fácilmente la función lógica de su

Los mantenedores de Redux le dirán "Oye, debes implementar la lógica de tu aplicación como múltiples reductores y múltiples eventos, que construirán diferentes partes de tu objeto" fusionado ".
Creo que es un enfoque incorrecto. Significa que no podrá alejarse de redux. Lo que estaba destinado a ser una herramienta para administrar su estado, se convierte esencialmente en una implementación de la lógica de su

Hola, profundizo en React / Redux durante unos días, entiendo la decisión tomada para elegir si cierta información debe promocionarse para almacenarla o mantenerse en el estado local del componente.

Pero, ¿y si una acción requiere ambas simultáneamente? Aquí está el caso de uso, que es muy común:

  1. [contexto] La tienda Redux es una sola hoja { modelItems: myModelItems } . Almacena en caché (parte de / una proyección de) el modelo de servidor
  2. [contexto] La vista está formada por un solo componente inteligente MyItemsView que muestra una lista de IU de los elementos almacenados / en caché. Cuando está montado, el componente activa una recuperación de elementos del modelo. Entrada de componente: myModelItems . Salida del componente: un activador de acción fetchModelItems . Componentes internos: state.busy y state.errorId
  3. [plan] Cuando MyItemsView activa fetchModelItems , se envía una solicitud HTTP al servidor para buscar el modelo y almacenarlo en la memoria caché. Esta acción asincrónica tiene 4 fases y tantos ganchos: onStarted (la solicitud HTTP está a punto de despegar, la carga giratoria comienza en el componente), onEnded (la respuesta HTTP aterriza, la carga giratoria se detiene en el componente , uno todavía no mira el estado de la respuesta), onFailed (se muestra una notificación de error en el componente) y onSucceed (la tienda Redux se actualiza y luego el modelo de caché que contiene se reenvía a el componente para renderizar)

Por lo tanto, cómo dividir el activador de acción fetchModelItems para que:

  • onStarted , onEnded y onFailed no llegan a la tienda Redux? Esto se debe a que onStarted y onEnded son estados de IU transitorios que no deberían tener interacción con el modelo de caché. Lo mismo ocurre con onFailed (el modelo de caché permanece sin cambios y la interfaz de usuario mostrará una notificación de error). MyItemsView representará el estado de la interfaz de usuario aquí, no el modelo en caché
  • onSucceed llega a la tienda Redux? Esto se debe a que ganó la lotería de la caché de modelos, se le otorga acceso a la fuente de la verdad, se duchará y se rehidratará, luego rendirá los myModelItems frescos en MyItemsView

Acerca de la implementación en mi intento actual, Redux Thunk se encarga del activador de acción fetchModelItems . Siento que elegí la ruta de Redux allí, y que ya no puedo cambiar de opinión para decir "simplemente pase el éxito asíncrono a la tienda de Redux, mantenga todo lo demás en el estado del componente React".

Desconcertado por esto, busco éxitos para almacenar, que reenvía al componente conectado (es decir, el contenedor Redux). Pero no hay ruleta de carga y un miserable cajero automático con mensajes de error registrados en la consola. No quiero definir store.ui.myItemsView.busy ni store.ui.myItemsView.errorId , sino obtener esa información en el estado del componente.

@pascalav :
Este es un rastreador de errores, no un sistema de soporte. Para preguntas de uso, use Stack Overflow o Reactiflux donde hay muchas más personas listas para ayudarlo; probablemente obtendrá una mejor respuesta más rápido. ¡Gracias!

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

timdorr picture timdorr  ·  3Comentarios

captbaritone picture captbaritone  ·  3Comentarios

mickeyreiss-visor picture mickeyreiss-visor  ·  3Comentarios

vraa picture vraa  ·  3Comentarios

olalonde picture olalonde  ·  3Comentarios