4 ms·
How to model application flows in React with finite state machines and XState
- dfabulich 5y agoThis article is about how to use XState in a React application, but says almost nothing about why XState is a good solution for React components. Here's the entire justification for adopting XState in React: > Instead of having that imperative business logic scattered around the code, we can define it in a flow chart that everyone from developers up to stakeholders can see and understand. This only works for trivial flow charts, i.e. demos in blog posts. Once you have a non-trivial application, the flow chart becomes too big to read/understand. And even for trivial problems, where the flow charts are legible, you're not buying anything by looking at the flow chart, precisely because the problem was already trivial. Just let each React component manage its own state with useState. P.S. Did you know that you can pass a function to useState? It's pretty handy when you want to code an "event transition." <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
- code_biologist 5y agoI can't speak for XState specifically, but I will say that state machines shared across the frontend and backend are a great way to manage complex workflows. The guarantees that come with a state machine help to stupidproof a whole lot of application logic.
- midrus 5y ago> This only works for trivial flow charts, i.e. demos in blog posts This applies to everything. Real life projects are always more complicated. I'd like to see how the same real life application compares vs just using useState. I've been on both end of this. Applications where people went crazy "ReDuXAlLThEThiNgs" and become an unmanageable disaster and applications where people went "We just need context and hooks" and also became a mess.
- ojkelly 5y ago> Real life projects are always more complicated. Complexity is the best reason to use an FSM. If your app is complicated, communicating how it works and can go wrong is also complicated. FSM's make that easier by codifying the complexity into something that can be reasoned about. > I'd like to see how the same real life application compares vs just using useState. If your app isn't complicated, I'd just useState. And in the apps where it is complicated, composing FSM's is as helpful as using local state for components who's state is local. Ie, some components can just useState, and mind their own business. Like, don't rearchitect your app because someone on the internet said FSM's are all the rage now. Do it because explaining how it works, and how a new feature integrates is a non-trivial task. Or because your stakeholders have a deep input on how the app works, but can't understand the intricate details. Or because you're building something new, and you know it's going to be a sizeable application. I'd sum it up as FSM's are to state as Typescript is to JS. It helps document your intent, and prevent you from doing things you don't want.
- midrus 5y agoEverything starts simple. > If your app isn't complicated, I'd just useState Your very trivial example of a button with a counter, gets very complicated as soon as you need the counter value available outside of its children... like in a header or the sidebar, etc. See? Now tell me how you do this, without rerendering the entire application on each change. "Just use useState" works fine as long as it is local state, and you're sure it will stay local in the future. Which is also compatible with XState and any other solution as long as you don't go crazy like reduxallthethings.
- ojkelly 5y agoI don't think an FSM will own your entire state in any sufficiently complex app. Especially considering things like Apollo in the GraphQL world that excel at remote and local state. If you don't yet have an FSM controlling your UI, then it's hard to understand what it replaces. If you only have a few screens, then it's possibly more overhead than it's worth. When you start getting complex, and you can't hold every view and how to get to every other view in your head - then it starts to become useful. Start with the router. All the normal access rules can be implemented with an FSM. But additionally, you can pre-empt changes and block transitions before they happen. Next multi-step forms. The contents of the forms can stay in whatever state system you're using for them. You just need to expose enough information that you need in your state machine to transition between steps. I've found an FSM is a helpful place to store form state _per step_ when that step is completed. And finally the rest of your application flows (note not state). > Your very trivial example of a button with a counter, gets very complicated as soon as you need the counter value available outside of its children... like in a header or the sidebar, etc. See? Now tell me how you do this, without rerendering the entire application on each change. Not the parent comment but, XState manages this problem the same way Redux does with a `useSelector` hook[0]. [0] https://xstate.js.org/docs/packages/xstate-react/#useselector-actor-selector-compare-getsnapshot https://xstate.js.org/docs/packages/xstate-react/#useselecto...
- ojkelly 5y agoSee this is what I love about finite state machines. You get the ability to see what your states and transitions look like. Not just you, the non-technical people on a project too. If you can't understand the state machine in your app, there's potential for a lot of unexpected states. FSM flow charts can get dense, but in the same way we compose react components, you can compose FSM's. You don't need a single FSM for your entire application. The router in a react app is often a state machine, and could be a finite state machine. Each major part of you're app could implement it's own finite state machine under that. The value of FSM's is that you can discuss the business logic with your stakeholders, often in language and with visual aids they understand. As opposed to not having it, and just making it up as we go along, and never considering the whole picture. FSM's have helped me explain and reconcile impossible states request by stakeholders (because they didn't understand how they were impossible, because they were sufficiently complex).
- midrus 5y agoI'm just getting started with XState and so far I'm loving it. Something that it is not that clear to me yet and I'd love an article about is how would you integrate it with form validation libraries, like react-hook-form, veevalidate (for Vue), etc. I've just seen some examples where the validation is implemented from scratch into the machine but I think this is just reinventing the wheel. Has anyone did something like this in real life? how did you find this integration? Any pains?
- imbnwa 5y agoXState seems more useful as a tool to help a non-technical layman, like a Product Manager, think through developing a prototype of a feature or something on their own. Engineers who have some notion of what the meaning of their code is know that FSMs tend to be encoded in a distributed fashion in an average code base. Whether or not its valuable to extract those into something more explicit is a case-by-case decision if that makes sense