Estoy trabajando en la investigación de una aplicación front-end de complejidad media. En este momento está escrito en javascript puro, tiene muchos mensajes diferentes basados en eventos que conectan algunas partes principales de esta aplicación.
Decidimos que necesitamos implementar algún tipo de contenedor de estado para esta aplicación en el marco de una mayor refactorización. Anteriormente tuve algo de experiencia con redux y ngrx store (que en realidad sigue los mismos principios).
Redux es una opción para nosotros, pero uno de los desarrolladores propuso usar una biblioteca basada en máquinas de estado, en particular, la biblioteca xstate .
Nunca trabajé con xstate, así que lo encontré interesante y comencé a leer la documentación y ver diferentes ejemplos. Parecía prometedor y poderoso, pero en algún momento entendí que no veo ninguna diferencia significativa entre él y redux.
Pasé horas tratando de encontrar una respuesta o cualquier otra información comparando xstate y redux. No encontré ninguna información clara, excepto algunos artículos como "get from redux to a state machine" , o enlaces a bibliotecas enfocadas en usar redux y xstate juntos (bastante raro).
Si alguien puede describir la diferencia o decirme cuándo los desarrolladores deben elegir xstate, puede hacerlo.
Creé XState, pero no les diré si usar uno u otro; eso depende de tu equipo. En cambio, intentaré resaltar algunas diferencias clave.
| redux | EstadoX |
|---|---|
| esencialmente un contenedor de estado donde los eventos (llamados acciones en Redux) se envían a un reductor que actualiza el estado | también un contenedor de estado, pero separa el estado finito (p. ej., "loading" , "success" ) del "estado infinito" o contexto (p. ej., items: [...] ) |
| no dicta cómo define sus reductores: son funciones simples que devuelven el siguiente estado dado el estado actual y el evento (acción) | un "reductor con reglas": define transiciones legales entre estados finitos debido a eventos, y también qué acciones deben ejecutarse en una transición (o al entrar/salir de un estado) |
| no tiene una forma integrada de manejar los efectos secundarios; hay muchas opciones de comunidad, como redux-thunk, redux-saga, etc. | hace que las acciones (efectos secundarios) sean declarativas y explícitas: son parte del objeto State que se devuelve en cada transición (estado actual + evento) |
| actualmente no tiene forma de visualizar transiciones entre estados, ya que no distingue entre estado finito e infinito | tiene un visualizador: https://statecharts.github.io/xstate-viz que es factible debido a la naturaleza declarativa |
| la lógica/comportamiento implícito representado en los reductores no se puede serializar de forma declarativa (por ejemplo, en JSON) | las definiciones de máquina, que representan lógica/comportamiento, se pueden serializar en JSON y leer desde JSON; esto hace que el comportamiento sea muy portátil y configurable por herramientas externas |
| no es estrictamente una máquina de estado | se adhiere estrictamente a la especificación W3C SCXML: https://www.w3.org/TR/scxml/ |
| depende del desarrollador para evitar manualmente los estados imposibles | utiliza gráficos de estado para definir de forma natural los límites para el manejo de eventos, lo que evita estados imposibles y puede analizarse estáticamente |
| alienta el uso de un único almacén atómico "global" | alienta el uso de un enfoque similar al modelo Actor, donde puede haber muchas instancias de "servicio"/gráfico de estado jerárquico que se comunican entre sí |
Agregaré más diferencias clave a los documentos esta semana.
La máquina de estado no le dice (obliga) a tener un flujo de datos unidireccional. No tiene nada que ver con el flujo de datos. Se trata más de restringir los cambios de estado y de las transiciones de estado. Por lo tanto, generalmente solo algunas partes de la aplicación se diseñarían con máquinas de estado, solo si necesita restringir/prohibir algunos cambios de estado y está interesado en las transiciones.
Tenga en cuenta que con las máquinas de estado, si por alguna razón (dependencia de API externa, etc.), existe la posibilidad de que la aplicación se bloquee en un estado en el que no puede pasar a otro estado debido a restricciones, debe resolverlo.
Pero si solo está interesado en el estado de la última aplicación en sí, en lugar de las transiciones de estado , y las restricciones de estado no importan, entonces es mejor que no use la máquina de estado y actualice directamente el estado ( aún puede envolver el estado en una actualización de clase Singleton a través de clases de acción ).
Por otro lado, Redux es un marco de arquitectura unidireccional . Las arquitecturas unidireccionales lo obligan a tener una sola dirección de flujo de datos. En Redux, comienza con User->View->(Action)->Store->Reducer->(Middleware)->Store->(State)->View . Al igual que State Machines, puede desencadenar efectos secundarios con Middlewares en Redux. Puede restringir/prohibir las transiciones de estado, si lo desea. A diferencia de State Machine , Redux fuerza el flujo de datos unidireccional, ¡ puro ! funciones reductoras, objetos de estado inmutables, estado de aplicación único observable.
algunos de mis puntos a continuación.