Redux: ¿Cuáles son las desventajas de almacenar todo su estado en un solo átomo inmutable?

Creado en 10 feb. 2016  ·  91Comentarios  ·  Fuente: reduxjs/redux

Entiendo que este es el principio subyacente a todo redux, y que viene con todos estos increíbles beneficios que ya son bastante conocidos.

Sin embargo, creo que un lugar en el que carece redux es que no describe abiertamente las desventajas conceptuales de usar esta arquitectura. Quizás esta sea una buena opción ya que desea que las personas no se alejen debido a los aspectos negativos.

Solo tengo curiosidad porque se aplica no solo a redux, sino de alguna manera a otras cosas como Om , datomic y que hablan de darle la vuelta a la base de datos . Me gusta redux, me gusta Om, me interesa la datómica y realmente me gustó esa charla.

Pero a pesar de todas las búsquedas que he hecho, es difícil encontrar personas críticas con la única tienda inmutable. Este es un ejemplo, pero parece tener un problema más con la verbosidad de redux que con la arquitectura real.

Lo único en lo que puedo pensar es que quizás se necesita más memoria para seguir almacenando copias de su estado, o que es un poco más difícil crear prototipos rápidamente con redux.

Debido a que ustedes probablemente hayan pensado mucho más en esto que yo, ¿podrían ayudarme a dilucidar esto?

discussion docs question

Comentario más útil

Redux es básicamente una fuente de eventos donde hay una sola proyección para consumir.

En los sistemas distribuidos, generalmente hay un registro de eventos (como Kafka) y varios consumidores que pueden proyectar / reducir este registro en múltiples bases de datos / tiendas que están alojadas en diferentes servidores (normalmente, una réplica de base de datos es en realidad un reductor). Entonces, en un mundo distribuido, la carga y el uso de la memoria están ... distribuidos, mientras que en Redux, si tiene cientos de widgets que tienen su estado local, todo esto se ejecuta en un solo navegador, y cada cambio de estado tiene una sobrecarga debido a inmutable actualizaciones de datos.

En la mayoría de los casos, esta sobrecarga no es un gran problema, sin embargo, cuando se montan entradas de texto en una forma de estado no tan buena y se escribe rápido en un dispositivo móvil lento, no siempre es lo suficientemente eficaz.

Representar ese estado desde la parte superior, en mi experiencia, no es conveniente y tampoco siempre tiene el rendimiento suficiente (al menos con React, que probablemente no sea la implementación de VDom más rápida). Redux resuelve esto con connect pero aún así, a medida que aumenta el número de conexiones, puede convertirse en un cuello de botella. Hay soluciones

Además, las estructuras de datos persistentes como ImmutableJS no siempre ofrecen el mejor rendimiento en algunas operaciones, como agregar un elemento en un índice aleatorio en una lista grande (vea mi experiencia en la representación de listas grandes aquí )

Redux incluye tanto el registro de eventos como la proyección porque es conveniente y está bien para la mayoría de los casos de uso, pero podría ser posible mantener un registro de eventos fuera de redux y proyectarlo en 2 o más tiendas redux, agregue todas estas tiendas redux a reaccionar contexto bajo diferentes claves, y tener menos sobrecarga especificando a qué tienda queremos conectarnos. Esto es absolutamente posible, sin embargo, esto haría que api y devtools sean más difíciles de implementar, ya que ahora necesita una distinción clara entre la tienda y el registro de eventos.


También estoy de acuerdo con @jquense

Los beneficios de una fácil hidratación, instantáneas, viajes en el tiempo, etc., solo funcionan si no hay otro lugar en el que viva el estado importante. En el contexto de React, esto significa que debe almacenar el estado, que pertenece correctamente a los componentes en la Tienda, o perderá muchos beneficios. Si desea poner todo en Redux, a menudo termina siendo engorroso y detallado, y agrega un molesto nivel de indirección.

El montaje de cualquier estado en la tienda Redux requiere más texto estándar. La arquitectura de Elm probablemente resuelve esto de una manera más elegante, pero también requiere una gran cantidad de repetición.

Pero tampoco es posible o eficaz hacer que todo el estado esté controlado. A veces usamos bibliotecas existentes para las que es difícil construir una interfaz declarativa. Algunos estados también son difíciles de montar en la tienda redux de una manera eficiente, que incluye:

  • Entradas de texto
  • Posición de desplazamiento
  • Tamaño de la ventana gráfica
  • Posición del mouse
  • Posición / selección del caret
  • URL de datos de lienzo
  • Estado no serializable
  • ...

Todos 91 comentarios

Esa es una gran pregunta. Intentaré escribir una respuesta completa mañana, pero primero me gustaría escuchar a algunos de nuestros usuarios. Sería bueno resumir esta discusión como una página oficial más adelante. Al principio no hicimos esto porque no conocíamos los inconvenientes.

¡Muchas gracias! Tenía muchas ganas de escuchar sobre esto.

Por cierto, animo a todos los que quieran contribuir a esta discusión a que también den una idea de lo que estaban construyendo con Redux para que sea más fácil entender el alcance de los proyectos.

Es una especie de pregunta difícil porque proyectos como OM y redux y otras bibliotecas de átomos de un solo estado mitigan activamente las desventajas. Sin la restricción de inmutabilidad, y el acceso controlado y cerrado, un átomo de estado único no es en absoluto diferente de adjuntar todos sus datos al window (cuyas desventajas son bien conocidas)

Sin embargo, específicamente para el enfoque de Redux, el mayor inconveniente para nosotros es que los átomos de un solo estado son una especie de todo o nada. Los beneficios de una fácil hidratación, instantáneas, viajes en el tiempo, etc. solo funcionan si _no_ hay otro lugar importante donde vive. En el contexto de React, esto significa que debe almacenar el estado, que pertenece correctamente a los componentes en la Tienda, o perderá muchos beneficios. Si desea poner todo en Redux, a menudo termina siendo engorroso y detallado, y agrega un molesto nivel de indirección.

Sin embargo, ninguno de estos inconvenientes ha sido particularmente prohibitivo para nosotros :)

Entonces, he estado mirando Redux, y este estilo de arquitectura, para modelar los estados del juego; Tengo interés en hacer mundos simulados al estilo Civ e historiales de juegos de mesa completamente grabados de manera más simple, en un contexto de navegador, lo cual es quizás un caso de uso inusual para algunos, pero dudo que alguien quiera que me detenga.

En ese contexto, me interesan los esfuerzos para administrar el tamaño de la estructura de datos históricos, mover partes de ella al servidor o al disco para guardarla, restaurar segmentos específicos, etc.

Con lo que he luchado, como nuevo usuario, la mayoría es tratar de superar tanto el cambio extremo (en mi humilde opinión) de estilo de codificación en Redux, y los cambios conceptuales al mismo tiempo; sigue siendo un poco abrumador incluso ahora, un mes y un cambio después de intentar profundizar en él; Estoy buscando en https://github.com/ngrx/store a continuación para llegar a los conceptos, pero con un estilo / sintaxis más familiar y más del resto del marco implícito / proporcionado.

Entiendo que para algunos, un marco es una muleta; pero algunos de nosotros los necesitamos; pocas personas estarán lo suficientemente en la cima de su juego como para tener opiniones sólidas y útiles, por lo que un framework es mejor que buscar a tientas en la oscuridad, ¿sabes? Así que ese es un punto para mí, un programador de mediana edad de nivel medio nuevo en los conceptos :)

Básicamente, Redux y sus videos me enseñaron cómo hacerlo en javascript sin procesar, pero como soy un programador con menos experiencia, todavía no tengo idea de cómo entregar un producto sin una guía adicional, así que hasta que vea ese ejemplo de algo terminado, simplemente pararse como:

No es tu culpa, pero sigue siendo un problema que me encantaría ayudar a resolver :)

Creo que la pregunta más importante que todavía tengo en este punto es, ¿dónde deberían ir los elementos no serializables como funciones, instancias o promesas? Me preguntaba sobre esto en Reactiflux la otra noche y no obtuve ninguna buena respuesta. También vi a alguien publicar http://stackoverflow.com/questions/35325195/should-i-store-function-references-in-redux-store .

Caso de uso para varias tiendas (tenga en cuenta que esta es la mejor que se me ocurre):

Una aplicación que combina varias sub-aplicaciones juntas. Piense en algo como My Yahoo u otro producto de página de inicio personalizable. Cada widget deberá mantener su propio estado sin superposición entre los dos. Es probable que se asigne un equipo de producto a cada widget, por lo que es posible que no conozcan los efectos del código de otros en el entorno.

Reunidos, es probable que pueda lograr esto en Redux al violar algunas reglas y tener cuidado de propagar esas tiendas en algo como el contexto de React. Pero podría ser más fácil con un marco que maneja múltiples átomos de estado de forma predeterminada.

@gaearon estamos construyendo una plataforma comercial. Ya te he explicado una vez por qué una tienda no es adecuada para nosotros (después de la reunión de React.js en San Petersburgo). Intentaré explicarlo de nuevo en detalle (¿en la publicación de blog en medium?) Pero probablemente necesite ayuda debido a mis habilidades en inglés :) ¿Está bien si se lo envío a usted oa alguien más aquí para que lo revise en Twitter directamente mensajes cuando se hará? Sin embargo, no puedo nombrar la fecha exacta, pero intentaré escribir esta publicación pronto (probablemente a fines de este mes).

Y sí, todavía estamos usando Redux con múltiples tiendas al violar algunas reglas de los documentos como dijo @timdorr (a costa de eso, no podemos usar react-redux tan cómodamente en los casos en que necesitemos datos de varias tiendas como es en caso de una sola tienda)

Redux es básicamente una fuente de eventos donde hay una sola proyección para consumir.

En los sistemas distribuidos, generalmente hay un registro de eventos (como Kafka) y varios consumidores que pueden proyectar / reducir este registro en múltiples bases de datos / tiendas que están alojadas en diferentes servidores (normalmente, una réplica de base de datos es en realidad un reductor). Entonces, en un mundo distribuido, la carga y el uso de la memoria están ... distribuidos, mientras que en Redux, si tiene cientos de widgets que tienen su estado local, todo esto se ejecuta en un solo navegador, y cada cambio de estado tiene una sobrecarga debido a inmutable actualizaciones de datos.

En la mayoría de los casos, esta sobrecarga no es un gran problema, sin embargo, cuando se montan entradas de texto en una forma de estado no tan buena y se escribe rápido en un dispositivo móvil lento, no siempre es lo suficientemente eficaz.

Representar ese estado desde la parte superior, en mi experiencia, no es conveniente y tampoco siempre tiene el rendimiento suficiente (al menos con React, que probablemente no sea la implementación de VDom más rápida). Redux resuelve esto con connect pero aún así, a medida que aumenta el número de conexiones, puede convertirse en un cuello de botella. Hay soluciones

Además, las estructuras de datos persistentes como ImmutableJS no siempre ofrecen el mejor rendimiento en algunas operaciones, como agregar un elemento en un índice aleatorio en una lista grande (vea mi experiencia en la representación de listas grandes aquí )

Redux incluye tanto el registro de eventos como la proyección porque es conveniente y está bien para la mayoría de los casos de uso, pero podría ser posible mantener un registro de eventos fuera de redux y proyectarlo en 2 o más tiendas redux, agregue todas estas tiendas redux a reaccionar contexto bajo diferentes claves, y tener menos sobrecarga especificando a qué tienda queremos conectarnos. Esto es absolutamente posible, sin embargo, esto haría que api y devtools sean más difíciles de implementar, ya que ahora necesita una distinción clara entre la tienda y el registro de eventos.


También estoy de acuerdo con @jquense

Los beneficios de una fácil hidratación, instantáneas, viajes en el tiempo, etc., solo funcionan si no hay otro lugar en el que viva el estado importante. En el contexto de React, esto significa que debe almacenar el estado, que pertenece correctamente a los componentes en la Tienda, o perderá muchos beneficios. Si desea poner todo en Redux, a menudo termina siendo engorroso y detallado, y agrega un molesto nivel de indirección.

El montaje de cualquier estado en la tienda Redux requiere más texto estándar. La arquitectura de Elm probablemente resuelve esto de una manera más elegante, pero también requiere una gran cantidad de repetición.

Pero tampoco es posible o eficaz hacer que todo el estado esté controlado. A veces usamos bibliotecas existentes para las que es difícil construir una interfaz declarativa. Algunos estados también son difíciles de montar en la tienda redux de una manera eficiente, que incluye:

  • Entradas de texto
  • Posición de desplazamiento
  • Tamaño de la ventana gráfica
  • Posición del mouse
  • Posición / selección del caret
  • URL de datos de lienzo
  • Estado no serializable
  • ...

Esta pregunta que acabo de ver en SO:

http://stackoverflow.com/questions/35328056/react-redux-should-all-component-states-be-kept-in-redux-store

Echos cierta confusión que he visto sobre la gestión del estado de la interfaz de usuario y si el estado de la interfaz de usuario debe pertenecer al componente o ir a la tienda. # 1287 ofrece una buena respuesta a esta pregunta, pero no es tan aparente inicialmente y puede ser objeto de debate.

Además, esto podría ser un obstáculo si está tratando de implementar algo como esto https://github.com/ericelliott/react-pure-component-starter en el que cada componente es puro y no tiene voz en su propio estado .

Me resultó difícil usar el árbol de estado único de redux cuando necesitaba administrar los datos de varias sesiones. Tenía una cantidad arbitraria de ramas con una forma idéntica y cada una tenía múltiples identificadores únicos (dependiendo de dónde vinieran los datos, usaría una clave diferente). La simplicidad de las funciones reductoras y las funciones de reselección desaparecieron rápidamente cuando se enfrentaron a esos requisitos: tener que escribir captadores / definidores personalizados para apuntar a una rama específica se sintió demasiado complejo y plano en un entorno por lo demás simple y compostable. No sé si varias tiendas son la mejor opción para abordar ese requisito, pero algunas herramientas para administrar sesiones (o cualquier otro dato de forma idéntica) en un solo árbol de estado sería bueno.

Mayor probabilidad de colisiones de claves de estado entre reductores.
Las mutaciones y declaraciones de datos están lejos del código donde se usan los datos (cuando escribimos un código intentamos colocar declaraciones de variables cerca del lugar donde las usamos)

Permítanme comenzar con mi caso de uso particular: estoy usando Redux con virtual-dom, donde todos mis componentes de UI son puramente funcionales y no hay forma de tener un estado local para varios componentes.

Dicho esto, definitivamente la parte más difícil es atar en estado de animación . Los siguientes ejemplos tienen en cuenta el estado de la animación, pero gran parte de esto se puede generalizar al estado de la interfaz de

Algunas razones por las que el estado de la animación es incómodo para Redux:

  • Los datos de animación cambian con frecuencia
  • Las acciones específicas de animación contaminan el historial de acciones en su aplicación, lo que dificulta la reversión de acciones de una manera significativa
  • El árbol de estado de Redux comienza a reflejar el árbol de componentes si hay muchas animaciones específicas del componente
  • Incluso el estado de animación básico como animationStarted o animationStopped comienza a acoplar el estado a su IU.

Por otro lado, definitivamente existen desafíos para construir el estado de animación completamente fuera del árbol de estado de Redux.

Si intenta hacer animaciones usted mismo manipulando el DOM, debe tener cuidado con cosas como esta:

  • Las diferencias de virtual-dom no tendrán en cuenta la manipulación de su animación, como los estilos personalizados que establezca en el nodo; si establece algunos estilos en un nodo DOM, debe eliminarlos usted mismo si desea que desaparezcan.
  • Si realiza animaciones en el documento en sí, debe ser consciente de las actualizaciones de virtual-dom. Puede iniciar una animación en un nodo DOM, solo para descubrir que el contenido de ese nodo DOM se cambió a mitad de la animación.
  • Si realiza animaciones en el documento en sí, debe tener cuidado con los estilos y atributos de sobrescritura de virtual-dom que establezca en su nodo, y debe tener cuidado con los estilos y atributos de sobrescritura establecidos por virtual-dom

Y si intentas dejar que virtual-dom se encargue de toda la manipulación DOM (¡lo cual deberías!) Pero sin mantener el estado de animación en Redux, terminas con estos problemas difíciles como estos:

  • ¿Cómo expone el estado de la animación a sus componentes? Estado local en sus componentes? ¿Algún otro estado global?
  • Normalmente, la lógica de su estado está en los reductores de Redux, pero ahora tiene que agregar mucha lógica de representación directamente en sus componentes para saber cómo se animarán en respuesta a su estado. Esto puede ser bastante desafiante y detallado.

Actualmente hay proyectos increíbles como react-motion que hacen grandes avances en la solución de este problema _para React_, pero Redux no es exclusivo de React. Creo que tampoco debería serlo, mucha gente está trayendo su propia capa de vista e intentando integrarse con Redux.

Para cualquiera que tenga curiosidad, la mejor solución que he encontrado para Redux + virtual-dom es mantener dos átomos de estado: Redux mantiene el estado de la aplicación central, mantiene la lógica central para manipular ese estado en respuesta a acciones, etc. El otro estado es un objeto mutable que tiene un estado de animación (yo uso mobservable). El truco entonces es suscribirse a los cambios de estado de Redux _y_ cambios de estado de animación, y renderizar la interfaz de usuario en función de ambos:

/* Patch h for jsx/vdom to convert <App /> to App() */
import h from './h'
import { diff, patch, create } from 'virtual-dom'
import { createStore } from 'redux'
import { observable, autorun } from 'mobservable'
import TWEEN from 'tween.js'
import rootReducer from './reducers'
import { addCard } from './actions'
import App from './containers/App'

// Redux state
const store = createStore()

// Create vdom tree
let tree = render(store.getState())
let rootNode = create(tree)
document.body.appendChild(rootNode)

// Animation observable
let animationState = observable({
  opacity: 0
})

// Update document when Redux state 
store.subscribe(function () {
  // ... anything you need to do in response to Redux state changes
  update()
})

// Update document when animation state changes
autorun(update)

// Perform document update with current state
function update () {
  const state = store.getState()
  let newTree = render(state, animationState)
  let patches = diff(tree, newTree)
  rootNode = patch(rootNode, patches)
  tree = newTree
}

// UI is a function of current state (and animation!)
function render (state, animation = {}) {
  return (
    <App {...state} animation={animationState} />
  )
}

// Do some animations
function animationLoop (time) {
  window.requestAnimationFrame(animationLoop)
  TWEEN.update(time)
}
animationLoop()

new TWEEN.Tween(animationState)
      .to({ opacity: 100 }, 300)
      .start()

// Or when you dispatch an action, also kick off some animation changes...
store.dispatch(addCard())
/* etc... */

¡Gracias a todos por las excelentes respuestas! Manténlos viniendo.

Una cosa a tener en cuenta es que no pretendemos que Redux se use para _todos_ los estados. Solo lo que parezca importante para la aplicación. Yo diría que las entradas y el estado de animación deberían ser manejados por React (u otra abstracción de estado efímera). Redux funciona mejor para cosas como datos obtenidos y modelos modificados localmente.

@taggartbg

Me resultó difícil usar el árbol de estado único de redux cuando necesitaba administrar los datos de varias sesiones. Tenía una cantidad arbitraria de ramas con una forma idéntica y cada una tenía múltiples identificadores únicos (dependiendo de dónde vinieran los datos, usaría una clave diferente). La simplicidad de las funciones reductoras y las funciones de reselección desaparecieron rápidamente cuando se enfrentaron a esos requisitos: tener que escribir captadores / definidores personalizados para apuntar a una rama específica se sintió demasiado complejo y plano en un entorno por lo demás simple y compostable.

¿Le importaría crear un problema que describa su caso de uso con más detalle? Puede ser que exista una forma sencilla de organizar la forma del estado de manera diferente que le falta. En general, múltiples ramas con la misma forma de estado pero gestionadas por diferentes reductores es un anti-patrón.

@istarkov

Mayor probabilidad de colisiones de claves de estado entre reductores.

¿Le importaría explicar cómo sucede esto con más detalle? Normalmente, le sugerimos que ejecute un solo reductor en cualquier segmento de estado. ¿Cómo pueden ocurrir las colisiones? ¿Estás haciendo varios pases por el estado? Si es así, ¿por qué?

@gaearon @istarkov : ¿quizás lo que se quiere decir es que varios complementos y bibliotecas relacionadas podrían estar compitiendo por el mismo espacio de nombres de nivel superior? La biblioteca A quiere una clave superior llamada "myState", pero también la biblioteca B, etc.

Sí, este es un buen punto incluso si esto no es lo que quiso decir

@gaearon

¿Le importaría crear un problema que describa su caso de uso con más detalle? Puede ser que exista una forma sencilla de organizar la forma del estado de manera diferente que le falta. En general, múltiples ramas con la misma forma de estado pero gestionadas por diferentes reductores es un anti-patrón.

¡Estaría feliz de! Haré eso cuando tenga un momento.

Creo que definitivamente se lo considera un antipatrón, aunque tengo un reductor único compartido para administrar esas ramas. No obstante, siento que el paradigma que proporciona redux no está lejos de ser un caso de uso perfecto para serializar / deserializar ramas idénticas como estado inmutable. No veo por qué sería contrario al espíritu de redux construir algo como reselect con alguna lógica asumida para apuntar a ramas específicas por alguna clave.

Estaría feliz de conversar sobre eso fuera del hilo, podría muy bien estar equivocado.

@taggartbg : hablando completamente sin saber cómo se ve su código aquí. ¿Estás hablando de tratar de lidiar con un estado que se ve así?

{ groupedData : { first : {a : 1, b : 2}, second : {a : 3, b : 4}, third : {a : 5, b, 6} }

Parece que podría lidiar con eso en el lado del reductor teniendo una única función de reductor que toma la clave de identificación por grupo como parte de cada acción. De hecho, ¿ha mirado algo como https://github.com/erikras/multireducer , https://github.com/lapanoid/redux-delegator , https://github.com/reducks/redux-multiplex , o https://github.com/dexbol/redux-register?

Además, en el lado de la reselección, el hecho de que React-Redux ahora admita selectores por componente podría ayudar, ya que eso mejora los escenarios en los que está haciendo una selección basada en accesorios de componentes.

@gaearon

Una cosa a tener en cuenta es que no pretendemos que Redux se use para todos los estados. Solo lo que parezca importante para la aplicación. Yo diría que las entradas y el estado de animación deberían ser manejados por React (u otra abstracción de estado efímera). Redux funciona mejor para cosas como datos obtenidos y modelos modificados localmente.

Un desarrollador de React que lee los documentos y el tutorial ya tiene esta abstracción de estado efímera a su disposición, por lo que es posible que esto ya esté en mente al considerar dónde tiene sentido Redux para un proyecto.

Sin embargo, desde la perspectiva de un desarrollador con poca o ninguna experiencia con React que quiere adoptar un enfoque funcional de la interfaz de usuario, puede que no sea obvio qué estado pertenece a Redux. He realizado varios proyectos en los que al principio Redux y virtual-dom eran suficientes, pero a medida que la aplicación crecía en complejidad, esta otra "abstracción de estado efímera" se hizo necesaria. Esto no siempre es evidente la primera vez que agrega un reductor de animación con algunas banderas de animación básicas, pero más adelante se vuelve bastante complicado.

Sería bueno para los documentos mencionar qué estado es el adecuado para Redux y qué estado se resuelve mejor con otras herramientas. Puede ser redundante para los desarrolladores de React, pero podría ser muy beneficioso para otros desarrolladores tenerlo en cuenta al mirar Redux y planificar la arquitectura de su aplicación.

EDITAR: el título del problema es "¿Cuáles son las desventajas de almacenar todo su estado en un solo átomo inmutable?" Este "todo su estado en un solo átomo inmutable" es exactamente el tipo de redacción que termina obteniendo una gran cantidad de estados incorrectos en el árbol de Redux. La documentación podría proporcionar algunos ejemplos explícitos para ayudar a los desarrolladores a evitar este tipo de trampa.

@gaearon Tuvimos una conversación interesante en Cycle.js sobre las diferencias arquitectónicas entre un estado de un solo átomo y pipping. AQUÍ .

Sé que esto no está 100% relacionado con Redux, pero quería dar una perspectiva diferente de una implementación que usa flujos observables como un flujo de datos alrededor de una aplicación (para Cycle, la aplicación es un conjunto de funciones puras).

Debido a que todo en Cycle es un Observable, estaba teniendo dificultades para lograr que el estado pasara de un cambio de ruta a otro. Esto se debió a que el estado Observable no tenía un suscriptor una vez que se cambió una ruta y pensé por qué no implementar un estado de un solo átomo, por lo que cada vez que cambiara el estado en mi aplicación, informaría a la tienda de nivel superior, sin pasar por las tuberías ( vista terrible dibujos aquí ).

Con Cycle, debido a que los efectos secundarios ocurren en los controladores, generalmente tiene que hacer ese bucle desde el controlador de nivel superior hasta el componente y viceversa, por lo que quería omitir eso y volver directamente a los componentes que escuchan. Tomaba Redux como fuente de inspiración.

No es un caso que sea correcto o incorrecto, pero ahora hago la canalización y hemos descubierto un controlador de estado, tener la capacidad de canalizar mi estado a diferentes componentes según sea necesario es realmente flexible para refactorizar, crear prototipos y tener una sólida comprensión cada fuente de estado, cada consumidor y cómo se conocieron.

También los recién llegados a la aplicación (si entienden Cycle, por supuesto), pueden conectar fácilmente los puntos y dibujar muy rápidamente una representación visual en su mente de cómo se maneja y canaliza el estado y todo esto desde el código.

Perdón por adelantado si esto está totalmente fuera de contexto, quería demostrar cómo un paradigma diferente tuvo una conversación similar: smiley:

@timdorr

Cada widget deberá mantener su propio estado sin superposición entre los dos. Es probable que se asigne un equipo de producto a cada widget, por lo que es posible que no conozcan los efectos del código de otros en el entorno.

Creo que es mejor cuando el widget tiene su propio estado (tal vez incluso su propia tienda (¿redux?)) Para que pueda funcionar de forma independiente en cualquier aplicación (mashup-) y recibir solo algunas de sus propiedades. Piense en el widget del tiempo. Puede buscar y mostrar datos por sí mismo y recibir solo propiedades como ciudad, alto y ancho. Otro ejemplo es el widget de Twitter.

¡Gran discusión!

Principalmente, me resulta inconveniente combinar varias aplicaciones / componentes / complementos.

No puedo simplemente tomar un módulo que construí y lanzarlo en otro módulo / aplicación, ya que tendré que importar por separado sus reductores a la tienda de la aplicación, y tendré que ponerlo bajo una clave específica que mi módulo conoce. Esto también me limita a duplicar el módulo si uso @connect , porque se conecta a todo el estado.

Por ejemplo:

Estoy creando un mensajero que se parece a iMessage. Tiene un estado redux de currentConversationId etc. Mi componente Messenger tiene @connect(state => ({ currentConversationId: state.messenger.currentConversationId })) .

Quiero incluir este Messenger en una nueva aplicación. Tendré que import { rootReducer as messengerRootReducer } from 'my-messenger' y agregarlo a combineReducers({ messenger: messengerRootReducer }) para que funcione.

Ahora, si quiero tener dos instancias <Messenger> en la aplicación que tengan datos diferentes, no puedo, porque estoy obligado a state.messenger en el componente Messenger. Haciendotrabajar contra una porción específica de la tienda me hará usar un @connect .

Además, digamos que la aplicación que la contiene tiene un nombre de acción determinado que existe en el módulo my-messenger , habrá una colisión. Esta es la razón por la que la mayoría de los complementos redux tienen prefijos como @@router/UPDATE_LOCATION .

Algunas ideas aleatorias / locas:

1

@connect pueden conectarse a un segmento específico de la tienda, por lo que puedo incluir en mi aplicación varios <Messenger> s que se conectan a su propio segmento de datos, como state.messenger[0] / state.messenger[1] . Debería ser transparente para <Messenger> que aún se sigue conectando a state.messenger , sin embargo, la aplicación que lo contiene puede proporcionar el segmento mediante algo como:

@connect(state => ({ messengers: state.messengers }))
class App extends Component {
  render() {
    return (
      <div>
        {this.props.messengers.map(messenger =>
          <ProvideSlice slice={{messenger: messenger}}><Messenger /></ProvideSlice>
        }
      </div>
    )
  }
}

Hay un problema al usar entidades normalizadas globales, state.entities también deberá estar presente, por lo que junto con el estado dividido, todo el estado debe estar presente de alguna manera. ProvideSlice puede establecer un contexto desde el que Messenger @connect podrá leer.

Otro problema es cómo vincular acciones activadas por componentes en <Messenger> que solo afectan a ese segmento. Tal vez tenga @connect debajo de ProvideSlice ejecutar mapDispatchToProps acciones solo en esa parte del estado.

2

Combine las definiciones store y reducer , por lo que cada reductor también puede ser independiente. Almacenar suena como un controlador mientras que un reductor es una vista. Si adoptamos el enfoque de react, "todo es un componente" (a diferencia del controlador / directiva de angular 1.x), puede permitir que los componentes y sus estados / acciones sean realmente independientes. Para cosas como entidades normalizadas (es decir, 'estado global'), se puede usar algo como el contexto de React, y se puede acceder a él a través de todas las acciones (por ejemplo, getState en thunk ) / componentes conectados.

@elado La idea más inteligente que he visto por ahora es https://medium.com/@timbur/react -automatic-redux-Suppliers-and-replicators-c4e35a39f1

Gracias @sompylasar. Estoy un poco en un cajero automático de viaje por carretera, pero cuando tenga la oportunidad, planeo escribir otro artículo que describa los proveedores de manera más sucinta para aquellos que ya están familiarizados con React y Redux. Cualquiera que ya esté familiarizado debería encontrarlo increíblemente simple / fácil. :)

@gaearon aún quisiera escuchar sus pensamientos sobre esto.

Mi mayor problema es que es más difícil componer, reutilizar, anidar y, en general, mover los componentes del contenedor porque hay dos jerarquías independientes al mismo tiempo (vistas y reductores). Tampoco está del todo claro cómo escribir componentes reutilizables que usen Redux como detalle de implementación o quieran proporcionar una interfaz compatible con Redux. (Hay diferentes enfoques). Tampoco me impresiona que cada acción tenga que ir "hasta el final" en lugar de hacer un cortocircuito en alguna parte. En otras palabras, me gustaría ver algo como el modelo de estado local de React pero respaldado por reductores, y me gustaría que fuera muy práctico y sintonizado con casos de uso reales en lugar de una hermosa abstracción.

@gaearon ¿ alguna idea sobre cómo comenzar a implementar dicho sistema?

@gaearon

En otras palabras, me gustaría ver algo como el modelo de estado local de React pero respaldado por reductores

Creo que la parte complicada es que el estado local de React está ligado al ciclo de vida de un componente, así que si intentas modelar el estado local en Redux, tienes una cuenta para "montar" y "desmontar". Elm no tiene este problema porque 1) los componentes no tienen ciclos de vida y 2) el "montaje" de una vista se deriva del modelo, mientras que en React, el estado local solo existe _después de que se ha montado una vista. (editar: es más preciso decirlo justo antes de montarlo, pero después de que ya se haya tomado la decisión de montar)

Pero como aludiste, la arquitectura Elm, que va "hasta el final" hacia arriba, tiene sus propios inconvenientes y no encaja muy bien con el ciclo de actualización y reconciliación de React (por ejemplo, requiere el uso liberal de optimizaciones shouldComponentUpdate() ... que se rompen si ingenuamente "reenvías" un método de envío dentro de render() .)

En cierto punto, tengo ganas de usar reductores + setState y llamarlo un día: D A menos que / hasta que React descubra una historia para externalizar el árbol de estados ... aunque tal vez eso es lo que realmente estamos discutiendo aquí

Supongo que esto es lo que @threepointone está tratando de resolver con https://github.com/threepointone/redux-react-local

@acdlite, el modelo conceptual de Elm funciona muy bien para el estado local, pero realmente parece una molestia usarlo en aplicaciones del mundo real donde tenemos que usar bibliotecas, enfocarnos en el montaje, manejar efectos de paralaje o lo que sea ... Ver https: // github.com/evancz/elm-architecture-tutorial/issues/49

@slorber Sí, estoy de acuerdo. ¿No es eso esencialmente lo que acabo de decir? :RE

Supongo que tus preocupaciones son ligeramente diferentes. _Si_ (gran "si") usaras la Arquitectura Elm en React, sin embargo, no creo que tengas los problemas que mencionas porque todavía tendríamos acceso a los ciclos de vida, setState como una escotilla de escape, etc.

Sí, estamos en la misma página @acdlite
La arquitectura Elm con React resolvería este problema.
Incluso Elm podría hacerlo en el futuro, ya que podría permitir el uso de ganchos vdom.

Sin embargo, la arquitectura de Elm requiere bastante repetición. Creo que no es realmente sostenible a menos que use Flow o Typecript para las acciones de envoltura / desenvoltura, y sería mejor tener una forma más simple de manejar este estado local, como la solución de @threepointone

Otra preocupación con la arquitectura Elm es que la acción anidada funciona muy bien para el estado del componente local, pero creo que no es una buena idea una vez que se necesita comunicación entre componentes desacoplados. Si widget1 tiene que desenvolver e introspectar acciones profundamente anidadas para encontrar algún evento disparado por widget2, hay un problema de acoplamiento. He expresado algunas ideas aquí y creo que usar Elm con 2 "buzones de correo" podría hacer el trabajo. Esto es también para lo que puede ayudar redux-saga en arquitecturas que no son elm con eventos planos.

Empiezo a tener una buena idea sobre cómo diseñar aplicaciones redux escalables e intentaré escribir algo al respecto cuando esté menos ocupado

@gaearon ¿Estás hablando de react-redux-provide en tu última publicación aquí? Se lo pregunto porque si lo está, según su respuesta, está claro que no lo ha examinado lo suficientemente de cerca.

Además, con respecto a la mención de @acdlite de externalizar el árbol de estado , este es exactamente el problema que los proveedores están diseñados para resolver.

La API proporcionada por el decorador provide es ciertamente una abstracción y sí, actualmente depende de redux , pero pensar que depende de redux es la forma incorrecta de piénselo, ya que en realidad es solo un "pegamento" entre los componentes y el árbol de estado, ya que context React aún no está completamente desarrollado. Piense en ello como un método ideal para manipular y representar los árboles estatales a través de actions y reducers (es decir, el estado de la tienda) como props , donde pueda para declarar esencialmente actions y reducers como propTypes (y / o contextTypes en el futuro) similar a cómo import cualquier otra cosa dentro de su aplicación. Cuando haces esto, todo se vuelve increíblemente fácil de razonar. context React podría potencialmente evolucionar para incluir estas características básicas, y en cuyo caso, tomaría 2 segundos completos para grep y eliminar @provide y import provide from 'react-redux-provide' para que esté luego se fue con componentes simples que ya no dependen de él. Y si eso nunca sucede, no es gran cosa porque todo seguirá funcionando perfectamente y de manera predecible.

Creo que estás simplificando demasiado el problema. Aún necesita resolver el montaje y desmontaje.

@acdlite ¿Tienes un ejemplo?

Si una de las cosas a las que te refieres es (por ejemplo) recuperar props de alguna base de datos basada en alguna id o lo que sea, esto (entre casi cualquier otra aplicación práctica que puedas imaginar) se puede lograr fácilmente con los proveedores. Una vez que haya terminado algunas otras cosas en las que estoy trabajando, me complacerá mostrarles lo fácil que es. :)

Puede ser interesante: comparación de implementaciones de estado reactivo .
Elm, Redux, CycleJS ... (trabajo en curso)

Otra posible necesidad de almacenamiento múltiple es cuando son posibles y necesarias múltiples _ líneas de tiempo_, _ viajes en el tiempo_, ubicaciones de ahorro y frecuencia de ahorro. Por ejemplo, user data y user actions que son específicos para un solo usuario y common data y group actions específicos para un grupo de usuarios (p. Ej., Proyecto multiusuario compartido o documento). Esto hace que sea más fácil separar lo que se puede deshacer (cambios en los datos personales) de lo que está arreglado (ediciones ya aumentadas por otros usuarios) y también facilita tener diferentes ciclos de guardado y / o sincronización.

Estamos en la fase de diseño / desarrollo temprano de una aplicación angular 1.x con mentalidad de desarrollo angular 2.0 y pensando en usar redux. En el pasado, hemos estado usando flux con varias tiendas que responden a algunos despachos comunes y a algunos despachos dedicados.

Redux me parece genial, pero no puedo razonar el concepto de tienda única para toda la aplicación. Como otros también han señalado anteriormente, tenemos una serie de grandes widgets que se supone que están alojados en diferentes aplicaciones de consumo y se necesitan almacenes de datos dedicados para cada uno de ellos.

A pesar de que los reductores se pueden dividir y pueden vivir con la función / widget que los usa, tenemos que agruparlos a todos cuando sea el momento de crear la tienda. Nos gustaría ver que nuestros widgets existen sin tener ninguna referencia directa / indirecta a reductores que no le interesan.

Realmente estamos deseando recibir alguna orientación en forma de documentación o un comentario para describir las mejores prácticas en tales situaciones antes de comenzar a usar redux en nuestra aplicación. Cualquier ayuda será muy apreciada. Gracias.

@VivekPMenon : ¿cuáles son sus preocupaciones específicas? ¿Tamaño del árbol estatal? ¿Ser capaz de realizar acciones de espacio de nombres / mantener aislados los reductores? ¿Capacidad para agregar o eliminar reductores dinámicamente?

Por lo que vale, acabo de completar una lista de enlaces que cataloga el ecosistema de complementos de Redux. Hay una serie de bibliotecas que intentan abordar algunos de esos conceptos de aislamiento / duplicación / alcance. Es posible que desee echar un vistazo a la página de reducción y la página de estado local / componente para ver si alguna de esas bibliotecas podría ayudarlo con sus casos de uso.

@markerikson. Muchas gracias por responder. Mi confusión gira principalmente en torno al segundo punto (aislamiento). Suponga que uno de nuestros equipos crea el widget A que se basa en el flujo y necesita usar la tienda para administrar su estado. Suponga que crearán un paquete jspm / npm y lo distribuirán. Lo mismo ocurre con otro equipo que crea el widget B. Estos son widgets / paquetes independientes y no necesitan tener una dependencia directa / indirecta entre sí.

En este contexto, en el mundo de flujo regular. Los widgets A y B tienen sus propias tiendas dentro de su paquete (pueden escuchar algunas acciones comunes, pero suponen que tienen más acciones que no son comunes). Y ambos widgets dependerán del despachador global. En el patrón redux, ¿dónde se crearía esa tienda (físicamente)? Los componentes de la interfaz de usuario del widget A y B deben usar la instancia de la tienda para escuchar los cambios y obtener el estado. En un flujo regular, operan en su propia instancia de tienda. Estoy tratando de visualizar cómo el concepto de tienda única va a jugar con esta situación.

@VivekPMenon esta es una pregunta válida que algunos de nosotros estamos tratando de resolver.

Puede obtener algunas ideas aquí: https://github.com/slorber/scalable-frontend-with-elm-or-redux

Además, eche un vistazo a mi respuesta sobre Redux-saga aquí: http://stackoverflow.com/a/34623840/82609

@slorber Muchas gracias por la orientación. Esperamos las ideas que surjan aquí https://github.com/slorber/scalable-frontend-with-elm-or-redux

@taggartbg ¿Finalmente abriste un problema? Estoy interesado en algo similar : cuando tengo un enrutador de reacción con diferentes subárboles independientes, me resulta problemático mantener el estado de la ruta anterior mientras navego a una nueva rama.

@slorber

Permítanme comenzar diciendo que la saga redux es un proyecto maravilloso con mucho trabajo y esto de ninguna manera intenta disminuir eso.

Pero no lo usaría en ninguno de mis proyectos en su estado actual. Aquí hay algunas razones por las que

Las sagas son apátridas

No se puede serializar el estado de un generador, tienen sentido mientras se ejecutan pero están completamente vinculados al estado de la saga. Esto provoca una serie de limitaciones:

  • No se pueden viajar en el tiempo generadores
  • No se puede rastrear el camino que llevó al estado actual de una saga.
  • No puedes definir un estado inicial
  • No puede separar la lógica empresarial del estado de la aplicación [*]
  • No puedes almacenar sagas

[*] Esto podría interpretarse como definir la lógica de negocios dentro de la definición del modelo de la aplicación, haciendo que la M y la C en MVC sean lo mismo, lo que podría considerarse como un antipatrón

El envío de acciones no es determinista

Una de las grandes ventajas de usar redux es mantener una comprensión simple de cómo reacciona el estado a una acción. Pero redux-saga hace que las acciones sean propensas a resultados inesperados, ya que no puedes saber en qué parte de la saga estás comenzando.

Estado serializable

El caso es que el estado actual de la saga tiene un impacto en el estado actual de la aplicación, y la gente se preocupa por mantener el estado serializable, pero ¿cómo se traduce eso a las sagas? Si no puede serializar completamente el estado, entonces no lo está _realmente_ serializando. Básicamente, no se puede recuperar el estado de una aplicación sin recuperar también la saga.


Almacenar lógica en el estado es malo, y en mi opinión, esto es lo que hace redux saga de alguna manera.

Está perfectamente bien asumir que el estado de su aplicación es específico de _su_ aplicación. Eso significa que también está bien suponer que el estado de la aplicación es predecible siempre que opere sobre _su_ aplicación. Esto significa que está bien mantener la información de la tienda que determina cómo se comporta su aplicación sin realmente guardar la lógica allí.

@eloytoro

Entiendo tus preocupaciones. Si observa los problemas de redux-saga, verá que se discuten estas cosas y que se pueden encontrar soluciones.

También tenga en cuenta que redux-saga opta por implementar con generadores, pero no es en absoluto un requisito para implementar el patrón de la saga, y hay pros y contras.

Hay un efecto de selección que le permite usar redux state dentro de su redux-saga, por lo que si no quiere ocultar el estado dentro de los generadores, simplemente puede poner su estado de saga dentro de redux-store directamente, pero implica más trabajo.

Hay herramientas de desarrollo de sagas que permiten rastrear la ejecución de las sagas.

Hay posibles soluciones para el viaje en el tiempo, pero aún no hay una implementación concreta.

Correcto. Un tema bastante extenso y muy interesante. He estado comparando diferentes enfoques de gestión estatal.

Tengo algunas cosas en mente al comparar:

  1. única fuente de verdad
  2. qué tan fácil / difícil es renderizar en el lado del servidor y alimentar los datos iniciales en el lado del cliente
  3. devtools como deshacer / rehacer y almacenamiento de historial persistente después de las recargas.
  4. animaciones, animaciones, animaciones. Siempre me pregunto _ "¿cómo funcionarían las animaciones con la solución a o b" _. Esta es una clave para mí, ya que los productos que estoy desarrollando están centrados en UX. Comparto muchas de las confusiones que tiene @jsonnull .
  5. reutilización de componentes dentro de otra aplicación
  6. hidratación de los datos de referencia (_major dolor_) para mantener la integridad (relacionada con la alimentación de los datos iniciales del lado del servidor o de cualquier otra fuente de datos)
  7. comunidad de otros desarrolladores para discusiones como esta

Así que estos son puntos de los que desconfío cuando pienso en la gestión estatal. Redux es el ganador al marcar la mayoría de las casillas. Conozco a Redux bastante bien y fueron las primeras cosas que me hicieron respirar con calma en el ámbito de los js del lado del cliente.

Los otros proyectos más notables que he estado investigando son el patrón SAM (_difícil de entrar en la mentalidad y sin herramientas_) y Mobx (_conocido por su almacenamiento mutable_).

Ambos comparten la idea de una única fuente de verdad y creo que es interesante ver cómo la manejan.

Mi investigación (limitada por supuesto) sobre Mobx está resultando en esto:

  1. Mobx (al igual que Redux) aboga por una fuente única de verdad pero como una clase con propiedades observables. Este concepto crea las diferencias con redux y flux como un todo:

    1. Mobx también aboga por las sub-tiendas (_anidado / parte del único global_). Para mí, se parece mucho a definir un esquema del lado del cliente. Es un poco molesto ya que probablemente también tenga un esquema en el servidor. Veo similitudes con redux-orm . AFAIK, las sub-tiendas están destinadas a pasarse a los componentes como accesorios (de esta manera, el componente no se basa en el estado de mapeo a los accesorios o cierta clave del árbol global). Sin embargo, pasar una sola propiedad rompe mi idea de "propiedades": deben ser descriptivas de lo que necesita el componente. Esto realmente me hace pensar si eso sería un problema si React propTypes se puede usar para definir la forma de la tienda que se pasa. Además: tener la tienda y las sub-tiendas como clases hace posible hacer referencia a los datos directamente sin necesidad de normalización, pero eso es un poco inútil si desea alimentar datos iniciales debido a:

    2. Sin embargo, la idea de almacenar como clase significa que el desarrollador no tiene la serialización lista para usar, lo que significa que ese es su trabajo si desea alimentar los datos iniciales.

  2. El historial y deshacer / rehacer se pueden lograr tomando instantáneas del estado después de que se haya cambiado. Pero necesita escribir serializador, deserializador usted mismo. Aquí se ofrece un ejemplo: https://github.com/mobxjs/mobx-reactive2015-demo/blob/master/src/stores/time.js
  3. Lo bueno de escribir serializadores es que puede omitir algunas cosas. parece un buen lugar para almacenar datos no persistentes relacionados con la animación. Entonces, si lo serializa, simplemente ignórelo y no tendrá un rehacer / deshacer lleno de pasos de animación.
  4. Mobx aboga por mantener las derivaciones de datos en la tienda (como métodos de la tienda) en contraposición al decorador reselect + connect . Esto me parece un poco incorrecto.
  5. Debido a su naturaleza observable, mobx facilita la definición de componentes puros eficientes. La comparación superficial de propiedades no es un problema porque el contenido es observable de todos modos.

Comparando SAM y Redux, me gusta pensar en cómo fluye la lógica:

  1. Redux:

    1. Definir una tienda

    2. Definir funciones que manejan cambios de tienda (reductores)

    3. Defina identificadores de eventos (acción redux) (tipo de acción redux) para cada cambio de tienda y ejecute un reductor específico cuando coincida

    4. Asigne el almacén a las propiedades del contenedor de componentes, pasando opcionalmente los controladores de la interacción del usuario (clic, tipo, desplazamiento, etc.) como funciones que simplemente desencadenan eventos / acciones de despacho.

    5. El componente desencadena un evento (acción redux) que se compara con todos los reductores

    6. Ríndete con el nuevo estado.

  2. SAM:

    1. Define una tienda.

    2. Defina una función de accesor / configurador para la tienda. Este establecedor acepta cualquier dato y, basándose puramente en los datos, intenta averiguar dónde colocarlo en la tienda y si necesita solicitar datos del servidor o conservarlos allí. No siempre es posible averiguar qué hacer con los datos con solo inspeccionarlos, por lo que a veces se utilizan identificadores / banderas (como isForgottenPassword ). Este establecedor también está destinado a validar los datos y almacenar los errores en su lugar. Una vez finalizado el setter -> volver a entregar con el nuevo estado.

    3. Defina funciones que acepten datos, los transformen (alternativa a redux reductores) y ejecuten el setter pasando los datos transformados. Esas funciones ahora tienen idea de la forma de la tienda. Solo conocen los datos que les han pasado.

    4. Asigne los datos del almacén a las propiedades del contenedor de componentes, pero también es obligatorio pasar los controladores de los controladores de interacción del usuario (hacer clic, escribir, desplazarse, etc.) Tenga en cuenta que estas son las funciones reales (conocidas como reductores en redux) y no funciones que ejecutan una llamada de despacho.

    5. Nota: no hay despacho de acciones, paso directo de reductores.

Entonces, todo redux, SAM y Mobx mantienen el estado en un solo lugar. La forma en que lo hacen trae sus propios contratiempos. Ninguno puede vencer a redux y su ecosistema hasta ahora.

El mayor inconveniente que veo es también el manejo del estado no serializable.
En mi caso, tengo una API de complemento y, por lo tanto, acciones y lógica que no tienen nada que ver con Redux pero necesitan interactuar con mi aplicación. Entonces, básicamente, necesito recrear inicialmente un montón de clases basadas en un estado dado.

Estoy trabajando en algunos conceptos sobre cómo manejar este tipo de estado no serializable de una mejor manera. Incluyendo volver a crearlo desde cualquier estado dado. Ya logré mover todo menos las referencias de función / objeto a la tienda. Lo que queda son objetos con sus propios ciclos de vida con una API definida que interactúan con mi aplicación y por lo tanto con mis acciones. - Se siente similar a los componentes de React, pero no para la representación de la interfaz de usuario, sino para la lógica personalizada.

No sé si habéis leído este artículo de Erik Meijer . Solo una simple cita:

Contrariamente a la creencia popular, hacer que las variables de estado sean inmutables no se acerca a eliminar los efectos imperativos implícitos inaceptables

Quizás es hora de volver a examinar todas estas tonterías de la inmutabilidad. Todo el mundo le dirá que es una pérdida de rendimiento cuando el árbol de un solo estado crece en tamaño. El patrón SAM hace que la mutación sea un ciudadano de clase principal del modelo de programación, muchas simplificaciones ocurren cuando se hace eso, desde no necesitar más Sagas, hasta todas estas máquinas de estado auxiliares necesarias para realizar un seguimiento de los efectos (por ejemplo, buscar).

El artículo realmente no discute a tu favor. Erik Meijer revisa "este sinsentido de la inmutabilidad" y lo acepta por completo . Sostiene que eliminar la mutación de estado es un primer paso básico , fundamental pero no suficiente. Su objetivo final es la eliminación completa de los efectos secundarios implícitos, lo que haría obsoleta cualquier gestión estatal (¡no habría estado que gestionar!).

Soy fanático del trabajo de Erik Meijer y leeré y escucharé con entusiasmo todo lo que tenga que decir, sin dejar de tener en cuenta que no opera bajo las mismas limitaciones comerciales, tecnológicas e intelectuales que yo.

El problema clave en la ingeniería de software es que todo el mundo parece creer que una asignación IS-A mutación. Los lenguajes de programación solo admiten asignaciones, la mutación se deja a la interpretación del programador.

Agregar un contenedor de función a un montón de asignaciones no se convertirá automáticamente en la mejor manera de mutar el estado. Eso es una tontería.

Hay una teoría detrás de la mutación de estado (de aplicación), se llama TLA +, por extraño que parezca ... Erik nunca menciona TLA + ...

JJ-

Permítanme dar más detalles, ya que parece haber mucha confusión. El artículo de Erik demuestra elocuentemente que los lenguajes de programación imperativos están algo rotos cuando se trata de estados mutantes. Creo que todos están de acuerdo en eso.

La pregunta es ¿cómo puede solucionarlo? ¿No estaría de acuerdo en que este es el tipo de problema que requiere un enfoque de " primer principio "?

Hay prácticamente un principio único en el que todos podemos estar de acuerdo en ciencias de la computación, el Dr. Lamport lo afirma como: "Gran parte de la ciencia de la computación se trata de máquinas de estado". y continúa: "Sin embargo, los científicos de la computación están tan concentrados en los lenguajes utilizados para describir la computación que en gran parte no son conscientes de que todos esos lenguajes describen máquinas de estado".

De hecho, todos los lenguajes de programación nos permiten especificar "máquinas de estado" independientemente de su semántica. Desafortunadamente, muchos lenguajes de programación están sesgados hacia la "acción" en lugar de la "acción de estado". Eso es por una buena razón, hay una gran clase de problemas que se codifican de manera mucho más eficiente con un formalismo basado en acciones (donde los estados de la máquina de estados pueden ignorarse en gran medida). Cuando los ignora, en esencia está diciendo que todas las acciones son posibles en cualquier estado dado, lo que todos sabemos que no es generalmente cierto.

Puedes reírte tanto como quieras del ejemplo jaja de Erik:
// prints Ha var ha = Ha(); var haha = ha+ha;

pero todo lo que dice es que estás tomando la acción incorrecta en un estado dado. Nada más y nada menos.

¿Qué aporta la programación funcional a la mesa? no mucho en absoluto. Expresa de una manera muy complicada la relación entre realizar una acción y los resultados que podría tener. Es como tratar de lanzar una flecha (incluso una flecha monádica inteligente) en un laberinto gigante y esperar que logres tu objetivo.

TLA + ofrece una forma mucho más natural de lidiar con los efectos, primero porque tiene una idea clara de qué es un paso y cómo se relaciona la mutación con la acción. Eres libre de ignorar TLA +, pero es un poco como si te estuvieras quejando de que trataste de enviar un cohete a la luna asumiendo que la tierra era plana y que era muy difícil dirigir la nave espacial. Sé que vivimos en un mundo en el que la gente cree que puede doblar la realidad, siempre y cuando suficiente gente crea lo que están diciendo ... eso todavía no te llevará a ninguna parte.

Así que, de nuevo, tendría mucha, mucha, mucha curiosidad por ver qué piensa Erik sobre TLA +, me conecté con él en LinkedIn y le hice la pregunta. Nunca obtuve una respuesta ... Después de todo, el Dr. Lamport solo recibió un premio Turing por eso, probablemente no valga la pena su tiempo.

Honestamente, @jdubray , estás en el límite del trolling en este punto. Ha repetido sus argumentos docenas de veces en este hilo, en otros temas y en otros lugares. Has insultado a Dan ya la comunidad de Redux, has agitado tus credenciales y sigues invocando las palabras "TLA +" y "Lamport" como si fueran el Santo Grial y la Respuesta a la Vida, el Universo y Todo. Usted ha insistido en que SAM es muy superior a Redux, pero sin escribir mucho en cuanto a aplicaciones de comparación significativas, a pesar de las numerosas invitaciones para mostrar evidencia. Realmente no vas a cambiar la opinión de nadie que no esté convencido a estas alturas. Sinceramente, le sugiero que pase su tiempo haciendo algo más productivo.

Voy a cerrar el hilo en este punto. Los comentarios pueden continuar, supongo, pero definitivamente no hay nada procesable aquí.

@markerikson Me gustaría mantener esta discusión incluso si no se dirige a ninguna parte, el tema me interesa bastante. Sería mejor aclarar sus comentarios tóxicos y mantener la buena discusión de código abierto.
Además de @antitoxic (sin juego de palabras) dejó bastante claro dónde el enfoque al que se refiere es útil o no, sabemos lo mal que han resultado los otros problemas debido a sus intervenciones, por lo que ya no tiene sentido escuchar

Está bien Mark, puedes eliminar mis comentarios, ¿por qué estropear una conversación tan brillante?

@jdubray solo tú lo ves brillante. Creo que todos sentimos que intentas vendernos algo sin más argumentos que "Lamport obtuvo un premio Turing, así que escúchame, ¡tengo razón!".

No digo TLA + o lo que sea que no sea bueno, y tal vez en el futuro alguien haga un mejor trabajo que tú vendiéndolo. Es solo la forma en que lo explica lo que no nos ayuda a entender en absoluto, y su tono condescendiente permanente no me invita a invertir tiempo en aprender sobre TLA +.

El artículo de Erik demuestra elocuentemente que los lenguajes de programación imperativos están algo rotos cuando se trata de estados mutantes. Creo que todos están de acuerdo en eso.

En realidad, siempre usas términos como I believe everyone agrees on that en todas tus publicaciones. Esto no es algo bueno, útil o acogedor para las personas. No todos estamos de acuerdo con usted por defecto, y la mayoría de nosotros no leemos y no leemos el artículo de Erik. Si no puede convencer a las personas de una manera acogedora, sin pedirles que lean toneladas de papel antes y hacer que se sientan tontos si no lo hacen o no están de acuerdo con usted, no ayudará a difundir sus ideas.

Eres libre de ignorar TLA +, pero es un poco como si te estuvieras quejando de que trataste de enviar un cohete a la luna asumiendo que la tierra era plana y que era muy difícil dirigir la nave espacial.

Esto definitivamente parece una analogía y ciertamente no un primer principio . En serio, ¿cree que esta afirmación debe considerarse como una "discusión brillante"?

Creo que las discusiones son en realidad más brillantes cuando no hablas en ellas, porque monopolizas toda la atención en TLA + y de hecho evitas que la gente no interesada en TLA + intente enviar su cohete a la luna con algo más concreto, que el promedio. la gente puede entender, como Redux.

Todavía no digo que TLA + no valga la pena, solo lo estás hablando de la manera incorrecta, con las personas equivocadas. ¿Quizás si Erik no te respondió, es porque tampoco te puede entender? ¿Quizás eres tan inteligente que solo Lamport puede entenderte? ¿Quizás en el futuro ganes un premio Turing? No lo sé, pero una cosa segura es que la discusión actual no trae nada a la mesa.

Tal vez haga como @gaearon y cree tutoriales en video TLA + / SAM para egghead. Si puede explicar sus ideas de una manera muy simple, en menos de 2 horas de videos, y al final sus patrones hacen clic y se sienten útiles para los desarrolladores, usted gana. Redux hizo eso para mucha gente. Sólo "intentó" explicar teóricamente por qué SAM / TLA + es mejor que Redux, y proporcionó una implementación de TodoMVC de aspecto horrible. Aquí somos investigadores de CS, necesitamos material de hormigón. ¿Puede mostrarnos una aplicación, escrita en Redux vs escrita en SAM, donde la gente realmente sienta que la implementación de SAM es mejor? Ese no ha sido el caso hasta ahora.

@Niondir Se me ocurrió una forma de usar las sagas en los casos en los que necesitas recuperar un estado.
Es más como un patrón o un conjunto de reglas a seguir.

  • Separa tus sagas para que cada una de ellas no tenga más de un put . Si tienes sagas con más de put en ellas, divídelas y encadénalas con un efecto call . P.ej
function* mySaga() {
  yield put(action1());
  yield put(action2());
}

// split into

function* mySaga() {
  yield put(action1());
  yield call(myNextSaga);
}

function* myNextSaga() {
  yield put(action2());
}
  • Las sagas con efectos take deben dividirse en la lógica que sigue el take y el punto de inicio de la saga. P.ej
function* mySaga() {
  yield take(ACTION);
  // logic
}

// split it into

function* rootSaga() {
  yield takeLatest(ACTION, mySaga);
}

function* mySaga() {
  // logic
}
  • Para cada saga crea una especie de función de "punto de control", lo que significa que en el inicio lee del estado y desde allí call la saga que necesitas
function* rootSaga() {
  // emit all forks and take effects that need to run in the background
  yield call(recoverCheckpoint);
}

function* recoverCheckpoint() {
  const state = yield select();
  if (state.isFetching) {
    // run the saga that left the state like this
  }
}

La explicación de por qué esto funcionaría se basa en un conjunto de supuestos que generalmente son ciertos

  • take efectos de
  • No permitir más de una llamada de put por saga permite cambios atómicos en el estado, de la misma manera que una acción solo puede alterar el estado de una sola manera, una saga también se limita a esa capacidad, lo que en cierto modo crea una correlación entre sagas y despacho de acciones.

Dividir las sagas de esta manera también tiene algunos _efectos_ positivos

  • Las sagas son más reutilizables
  • Las sagas se alteran más fácilmente
  • Las sagas son más fáciles de entender

pero @slorber :

Mucha gente encuentra este ejemplo de "juego de pesca" bastante interesante de codificar ya que ilustra de primera mano cómo funciona SAM en su totalidad, incluida una representación de estado dinámico y el "predicado de la siguiente acción". NAP alivia la necesidad de Sagas y no requiere romper el principio # 1 de Redux, que es un árbol de estado único, pero ¿qué sé yo?

A veces, cuando estoy usando Ableton Live, el pensamiento aparece en mi cabeza "¿sería posible escribir la GUI de Ableton Live como una aplicación React / Redux?" Creo que la respuesta es no, sería demasiado difícil obtener un rendimiento aceptable. Hay una razón por la que está escrito en Qt y una razón por la que Qt tiene una arquitectura de señales / ranuras.

He estado usando React / Redux con Meteor. Almaceno documentos mongo en el estado Immutable.js enviando acciones de Redux para las devoluciones de llamada a Mongo.Collection.observeChanges . Recientemente descubrí que al suscribirme a varios miles de documentos, la interfaz de usuario era extremadamente lenta en el inicio porque miles de acciones de Redux se enviaban cuando Meteor enviaba los resultados de la suscripción inicial uno por uno, lo que provocaba miles de operaciones Immutable.js y miles de reproducciones tan rápido como sea posible. Supongo que RethinkDB también funciona de esta manera, aunque no estoy seguro.

Mi solución fue crear un middleware especial que dejaría de lado esas acciones de recopilación y luego las enviaría en lotes a una velocidad limitada, de modo que pudiera agregar ~ 800 documentos en un solo cambio de estado. Resolvió los problemas de rendimiento, pero alterar el orden de los eventos es intrínsecamente riesgoso porque puede conducir a un estado inconsistente. Por ejemplo, tenía que asegurarme de que las acciones de estado de la suscripción se enviaran a través del mismo regulador, para que las suscripciones no se marcaran como listas antes de que todos los documentos se hubieran agregado al estado de Redux.

@ jedwards1211 Tuve un problema similar (muchos mensajes pequeños que compondrían los datos iniciales).

Resuelto de la misma forma haciendo una actualización por lotes. En lugar de un middleware, utilizo un mecanismo de cola personalizado (pequeño) (inserta todas las actualizaciones en una matriz y, a intervalos regulares, si hay algo para actualizar, actualícelas todas al mismo tiempo.

@andreieftimie sí, es más complicado en mi aplicación porque hay algunas interacciones de la interfaz de usuario que requieren actualizaciones inmediatas, como arrastrar y hacer zoom en los gráficos. Así que tengo que tener una capa de middleware para decidir si enviar una acción inmediatamente o ponerla en una cola para el envío por lotes.

Por lo que vale, tuve la idea de crear "ramas". Desafía totalmente el principio de una sola tienda, pero parecía un buen compromiso.

https://github.com/stephenbunch/redux-branch

@ jedwards1211 Creo que a medida que las aplicaciones crecen en complejidad, eventualmente existe la necesidad de dividir ciertos tipos de datos y ciertos tipos de actualizaciones para que ciertas tiendas no manejen la carga completa.

Digamos que hay un estado central que desea sincronizar con el backend, hay un estado de animación para que los componentes de la interfaz de usuario de su aplicación se muestren correctamente de acuerdo con las acciones actuales que se están realizando, y tal vez tenga algunos datos de depuración que está rastreando por separado.

En este ejemplo artificial, es posible que se construya todo esto a partir de una sola tienda Redux, pero dependiendo de cómo se diseñe, habrá algunas líneas borrosas entre las preocupaciones de varias ramas del árbol de estado y tal vez falta de claridad. con respecto a qué estado está destinada a interactuar una acción determinada.

Creo que es perfectamente razonable utilizar diferentes estrategias de gestión del estado de acuerdo con la forma en que desea que se establezca el alcance del estado y las características de rendimiento que espera de él. Redux está adecuadamente orientado al estado en el que es posible que desee deshacer o reproducir acciones, o serializar y volver más tarde. Para el estado de animación, puede usar una tienda mutable o una tienda reactiva si lo desea; habrá menos gastos generales de esa manera y no contaminará el estado de su aplicación con este estado de interacción transitorio (pero aún necesario).

Muy rápido, quiero hacer un punto sobre el uso de la próxima arquitectura de fibra React. Aquí hay un enlace , disculpas si mi comprensión está un poco desactualizada. Aproximadamente, la arquitectura de fibra reconoce que existen diferentes tipos de actualizaciones que se propagarán a través de un árbol de componentes de React, y hay diferentes expectativas con respecto a cuándo y cómo se realizarán estas actualizaciones. Desea que las actualizaciones de animación sean rápidas, receptivas y confiables, y no desea que las grandes actualizaciones de interacción introduzcan obstáculos en sus animaciones y demás.

Por lo tanto, la arquitectura de fibra divide las actualizaciones en paquetes de trabajo y las programa según una prioridad basada en el trabajo que se está realizando. Las animaciones son de alta prioridad, por lo que no se interrumpen y las actualizaciones mecánicas más lentas tienen una prioridad más baja.

Me salté muchos detalles sobre las fibras de React y probablemente me equivoqué en algunas cosas en el proceso, pero mi punto es que este es el tipo de enfoque granular que creo que es necesario para su almacén de datos con diferentes tipos de datos.

Si estuviera creando una aplicación compleja hoy, comenzaría con una clase de tienda de nivel superior similar a Redux respaldada por algunas tiendas diferentes. Aproximadamente:

  • El almacén de datos de nivel superior tiene una cola para las acciones entrantes
  • Las acciones son para acciones de animación que deben enviarse rápidamente o interacciones de aplicaciones que tienen menor prioridad
  • Las acciones de animación en la cola se envían a un backend observable desde un bucle requestAnimationFrame
  • Las acciones de interacción se envían a redux cuando se completan las acciones de animación de la cola

Esta historia parece bastante cercana a una solución de estado completa basada en Redux. Redux se adapta a los datos que desea ver después de una secuencia de acciones, y hay muchos otros estados que también necesitan un manejo cuidadoso.

@jsonnull Nunca tuve la necesidad de almacenar el estado de la animación en una tienda; el estado local siempre ha sido ideal para mis casos de uso de animación. Me gustaría saber si hay algunos casos de uso para los que el estado de animación local no es adecuado. Sin embargo, parece que tienen grandes ideas para la nueva arquitectura.

@ jedwards1211 Hay un par de casos en los que el estado de animación local no funciona. Te lo aseguro, no son casos con los que te encontrarás con cada aplicación, pero creo que surgen con bastante frecuencia.

En un caso, está utilizando una biblioteca diferente a Redux donde no tiene un estado local. (Ok, sí, sé que estoy haciendo un poco de trampa aquí.) Si está utilizando un enfoque de hiperescripto muy ajustado, sin dom virtual, componentes funcionales puros, entonces en lugar del estado local tendrá que pasar alguna animación estado al nodo raíz o al nodo que esté volviendo a renderizar.

En este caso, tener un árbol de estado con algunos detalles de animación establecidos le permitirá evitar la falta de estado local para que pueda activar animaciones, hacer que las animaciones se ejecuten durante un tiempo y más.

La clave aquí es que hay dos formas de hacer estas animaciones: hágalo como parte de su renderizado y mantenga intacta la metáfora "UI en función del estado", o mute el DOM por separado. Casi siempre, la mejor respuesta es simplemente volver a renderizar en lugar de mutar.


Ahora, para un ejemplo en el que tiene la capacidad de mantener algo de animación en el estado local, construyendo un juego de navegador con una interfaz de usuario basada en React encima.

  • Por lo general, conducirás el juego usando ticks ... el tiempo de juego comienza en 0 y se incrementa en cada cuadro. Las animaciones principales del juego se pueden realizar en lienzo o en WebGL donde no hay un estado local, por lo que basará la hora de inicio y el progreso de la animación en función de estos ticks.

Por ejemplo: un personaje de sprite tiene una animación que consta de 10 cuadros, y desea reproducir la animación durante ~ 400ms, por lo que cambiará el sprite dibujado cada 2 tics aproximadamente.

Sus ticks también podrían ser marcas de tiempo si desea una resolución más alta.

  • Su juego también puede pausarse, en cuyo caso es posible que desee detener algunas animaciones realizadas en el lado de la interfaz de usuario de React.

En este ejemplo de juego, lo que no quieres hacer es incrementar tus tics como parte de una acción tick ... en su lugar, quieres incrementar los ticks por separado, posiblemente en una estructura observable. Y cuando envíe acciones de Redux, como el movimiento o el ataque de los caracteres del teclado, les pasará el tick actual o el tiempo actual, para que pueda registrar en qué tick ocurrió una acción y los componentes de la interfaz de usuario pueden registrar localmente a qué hora comenzó una animación. .

Ahora ha separado el estado de animación global del estado de interacción, y si desea hacer una "repetición" usando solo el estado Redux o repitiendo acciones, puede hacerlo, y no está agobiado por incrementar tics como parte de su estado. árbol.

En términos generales, también es mucho mejor coordinar las animaciones pasando los tiempos de inicio / parada a través de Redux y dejando que los componentes mantengan el resto del estado localmente.

Esto no solo se aplica a los juegos. Cualquier secuencia extendida de animaciones podría pasar por esto, como si quisieras hacer una serie de animaciones de larga duración en un sitio usando React.

@jsonnull genial, ese es un gran ejemplo, gracias por compartirlo.

Simplemente diría que en Redux simplemente no puede almacenar sus objetos de estado con enlaces entre sí. Por ejemplo, el usuario puede tener muchas publicaciones y la publicación puede tener muchos comentarios y quiero almacenar esos objetos de una manera:

var user = {id: 'user1', posts: [], comments: []}
var post = {id: 'post1', user: user, comments: []}
user.posts.push(post);
var comment = {id: 'comment1', post: post, user: user}
post.coments.push(comment)
user.comments.push(comment)
appState.user = user

Redux no permite el uso de jerarquías de objetos con referencias circulares. En Mobx (o Cellx), simplemente puede tener referencias de uno a muchos y de muchos a muchos con objetos y simplificó la lógica empresarial muchas veces

@bgnorlov No creo que nada en el paquete redux prohíba las referencias circulares como las que estás hablando, solo hacen que sea más difícil clonar tu state en tu reductor. Además, podría ser más fácil realizar cambios en el estado con referencias circulares si usa Immutable.js para representar su estado, aunque no estoy seguro.

También puede modelar relaciones en su estado redux utilizando claves externas, aunque entiendo que esto no es tan conveniente como usar referencias de objetos similares a ORM:

var user = {id: 'user1', postIds: [], commentIds: []}
var post = {id: 'post1', userId: user.id, commentIds: []}
user.postIds.push(post.id);
var comment = {id: 'comment1', postId: post.id, userId: user.id}
post.commentIds.push(comment.id)
user.commentIds.push(comment.id)
appState.userId = user.id
appState.posts = {[post.id]: post}
appState.comments = {[comment.id]: comment}

// then join things like so:
var postsWithComments = _.map(appState.posts, post => ({
  ...post,
  comments: post.commentIds.map(id => appState.comments[id]),
})

@ jedwards1211 para clonar el estado con referencias circulares en redux, reducer debe devolver cada nueva copia de un objeto afectado por los cambios. Si la referencia al objeto cambia, el objeto relacionado también debe ser una nueva copia y esto se repetirá de forma recursiva y generará un estado completamente nuevo en cada cambio. Immutable.js no puede almacenar referencias circulares.
Con el enfoque de normalización, cuando algún controlador de eventos necesita algunos datos, requiere cada vez tomar el objeto por su ID del estado global. Por ejemplo, necesito filtrar los hermanos de tareas en algún lugar del controlador de eventos (las tareas pueden tener una estructura jerárquica) Con redux, necesito enviar el procesador para obtener acceso al estado de la aplicación

var prevTask = dispatch((_, getState)=>getState().tables.tasks[task.parentId]).children.map(childId=>dispatch((_, getState)=>getState().tables.tasks[childId])).filter(task=>...) [0]

o con selectores

var prevTask = dispatch(getTaskById(task.parentId)).children.map(childId=>dispatch(getTaskById(childId)).filter(task=>...)[0]

y este texto estándar convierte el código en un desastre en comparación con la versión de mobx cuando simplemente puedo escribir

var prevTask = task.parent.children.filter(task=>...)[0]

@ jedwards1211 , @bgnorlov : FWIW, esta es una de las razones por las que me gusta Redux-ORM . Le permite mantener su tienda Redux normalizada, pero simplifica la realización de esas actualizaciones y búsquedas relacionales. De hecho, ese último ejemplo es básicamente idéntico a Redux-ORM.

Acabo de escribir un par de publicaciones en el blog que describen los conceptos básicos de Redux-ORM , así como los conceptos básicos y el uso avanzado .

@markerikson genial, ¡gracias por el consejo!

@gaearon

Una cosa a tener en cuenta es que no pretendemos que Redux se use para todos los estados. Solo lo que parezca importante para la aplicación. Yo diría que las entradas y el estado de animación deberían ser manejados por React (u otra abstracción de estado efímera). Redux funciona mejor para cosas como datos obtenidos y modelos modificados localmente.

Encontré este comentario increíblemente útil. Sé que llego tarde a la fiesta, pero tal vez eso sea parte de mi punto. Más de un año desde que se publicó ese comentario y este sigue siendo el único lugar en el que he visto expresarse esta idea.

Viniendo de un fondo angular y decididamente sin flujo / redux, es muy difícil formular esa idea por su cuenta. Especialmente cuando muchos ejemplos aún crean acciones para cada tecla en un cuadro de texto. Me gustaría que alguien pusiera esa cita en texto de 50 px en la parte superior de cada página de documentación de Redux.

@leff De acuerdo. Había sintetizado esa idea exacta hace algún tiempo, pero no se menciona lo suficiente. Incluso si está utilizando Redux para la gestión del historial, a menudo hay una gran cantidad de estados efímeros que no necesitan sobrecargar su gestión de estados al estilo de Redux.

Eso no será necesariamente una sorpresa para las personas que han tenido la oportunidad de trabajar, por ejemplo, una aplicación de escritorio madura que hace mucho deshacer / rehacer. Pero para los océanos de recién llegados a estas ideas a través de Redux, será una revelación.

@bgnorlov, es un buen punto que es imposible almacenar referencias circulares con Immutable.js, ¡nunca pensé en eso! Sin embargo, creo que es una buena característica.

En estos días tendemos a almacenar casi todo en Redux, incluso si se trata de un estado específico de vista transitorio que nunca usamos fuera de su contexto (por ejemplo, estado para una instancia redux-form ). En la mayoría de los casos, podríamos sacar dicho estado de redux sin sufrir ningún problema. Pero la ventaja es que está ahí en caso de que alguna vez necesitemos componentes externos para responder en el futuro. Por ejemplo, podríamos tener algún ícono en la barra de navegación que cambia cuando algún formulario tiene errores o se está enviando.

Yo diría que lo más importante a tener en cuenta es que poner todo el estado normalizado en Redux (es decir, cualquier cosa que deba unirse para representar vistas) hará que sea más fácil de usar. El estado que no necesita unirse con nada probablemente puede vivir fuera de Redux sin causarle dificultades, pero generalmente tampoco está de más ponerlo en Redux.

FWIW, los documentos señalan que no todo tiene que ir a Redux, según http://redux.js.org/docs/faq/OrganizingState.html#organizing -state-only-redux-state.

Ha habido bastante charla en línea sobre para qué es "apropiado" Redux. Algunas personas ven los beneficios de poner literalmente todo en Redux, otras encuentran que es demasiado complicado y solo quieren almacenar los datos recuperados de un servidor. Entonces, definitivamente no hay una regla fija aquí.

Como siempre, si la gente tiene ideas para mejorar los documentos, los RR.PP. son bienvenidos :)

Si alguna vez necesita reutilizar reductores y poder asignar "sub-estados" en su estado redux, desarrollé un complemento para hacerlo sin esfuerzo (con integración React)

https://github.com/eloytoro/react-redux-uuid

@eloytoro En mi opinión, si tiene problemas con algún reductor de terceros que tenga tipos de acción codificados o una ubicación en el estado, debe abrir un problema en el proyecto ... en poco tiempo se convertirá en una práctica de diseño inaceptable a medida que las personas aprendan el reductor / acción reutilizable patrón de creador.

@eloytoro Iba a escribir algo así. ¡Muchas gracias por la referencia!

@ jedwards1211 Creo que tienes una idea equivocada. No he mencionado reductores de terceros o problemas con ellos de ninguna manera, solo trato de mostrar cómo mi fragmento puede resolver el problema para hacer que los reductores sean reutilizables en colecciones con tamaños dinámicos

@avesus espero que funcione para ti

@eloytoro ah, eso tiene más sentido.

El año pasado creé un juego bastante complejo usando Redux. También he participado en otro proyecto que no usa Redux, sino un marco minimalista personalizado que separa todo en UI Stores y Server Stores (incluidas las entradas). Sin entrar en demasiados detalles, mis conclusiones hasta ahora son las siguientes:

El estado único siempre es mejor, sin embargo, no se exceda. Obtener cada keyDown () a través de la tienda y volver a la vista es simplemente confuso e innecesario. Por lo tanto, los estados transitorios deben ser manejados por estados de componentes locales (como React).

Creo que desde que la reducción y la reacción inflamaron la web observable, la cantidad de buena animación en las páginas disminuyó.

@ mib32 ¡puede que tengas razón! Con suerte, la gente eventualmente se acostumbrará a crear una buena animación en React.

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

Temas relacionados

timdorr picture timdorr  ·  3Comentarios

cloudfroster picture cloudfroster  ·  3Comentarios

olalonde picture olalonde  ·  3Comentarios

benoneal picture benoneal  ·  3Comentarios

dmitry-zaets picture dmitry-zaets  ·  3Comentarios