I am working on investigation of one front-end application of medium complexity. At this moment it is written in pure javascript, it has a lot of different event-based messages connecting few main parts of this application.
We decided that we need to implement some kind of state container for this application in scope of further refactoring. Previously I had some experience with redux and ngrx store (which actually follows the same principles).
Redux is an option for us, but one of the developers proposed using a state-machine based library, in particular the xstate library.
I've never worked with xstate, so I found it interesting and started reading documentation and looking at different examples. Looked promising and powerful, but at some point I understood that I don't see any significant difference between it and redux.
I spent hours trying to find an answer, or any other information comparing xstate and redux. I didn't find any clear information, except some articles like "get from redux to a state machine", or links to libraries focused on using redux and xstate together (quite weird).
If someone can describe the difference or tell me when developers should choose xstate - you are welcome to.
I created XState, but I'm not going to tell you whether to use one over the other; that depends on your team. Instead, I'll try to highlight some key differences.
Redux | XState |
---|---|
essentially a state container where events (called actions in Redux) are sent to a reducer which update state | also a state container, but separates finite state (e.g., "loading" , "success" ) from "infinite state", or context (e.g., items: [...] ) |
does not dictate how you define your reducers - they are plain functions that return the next state given the current state and event (action) | a "reducer with rules" - you define legal transitions between finite states due to events, and also which actions should be executed in a transition (or on entry/exit from a state) |
does not have a built-in way to handle side-effects; there are many community options, like redux-thunk, redux-saga, etc. | makes actions (side-effects) declarative and explicit - they are part of the State object that is returned on each transition (current state + event) |
currently has no way to visualize transitions between states, since it does not discern between finite and infinite state | has a visualizer: https://statecharts.github.io/xstate-viz which is feasible due to the declarative nature |
the implicit logic/behavior represented in reducers can't be serialized declaratively (e.g., in JSON) | machine definitions, which represent logic/behavior, can be serialized to JSON, and read from JSON; this makes behavior very portable and configurable by external tools |
not strictly a state machine | adheres strictly to the W3C SCXML specification: https://www.w3.org/TR/scxml/ |
relies on the developer to manually prevent impossible states | uses statecharts to naturally define boundaries for handling events, which prevents impossible states and can be statically analyzed |
encourages the use of a single, "global" atomic store | encourages the use of an Actor-model-like approach, where there can be many hierarchical statechart/"service" instances that communicate with each other |
I will add more key differences to the docs this week.