This article is about React-Machinery, a library for creating and using state machines in react to control UI. Find the full source on github State is everywhere, and itās an especially hot topic in the web development community. We have libraries like to help manage global state, but on the component level we can go further and harness some good old fashioned computer science. redux Almost all UI components have a specific set of states they can be in. Simple components like dropdowns have , , and states. Complex views like a youtube video component have many states, like , , āāand many substates like if the volume control is , or if closed captions are enabled. This is not limited to UI eitherā any kind of application, object or function can be . unselected in selection selected playing paused loading expanded stateful As developers we often model these states using and While this is not bad per se, there are some problems with this approach: boolean variables if statements. combinations of boolean expressions can be tricky to understand and communicate as requirements change, these branching if statements can start to produce possibly unwanted side effects Ever had one of those bugs where for some reason, two completely different parts of state come together in an unexpected way to produce a weird effect? Iāve had this on almost every kind of project Iāve worked on, from games to SPAs to REST backends. Fortunately computer science provides a very nice solution to this class of problems, aptly named . Finite State Machines Finite State Machines > Combinational Logic First of all, roughly speaking a finite state machine is: A ( ) or ( , plural: ), , or simply a , is a mathematical . It is an that can be in exactly one of a finite number of at any given time. The FSM can change from one state to another in response to some external ; the change from one state to another is called a . An FSM is defined by a list of its states, its initial state, and the conditions for each transition. finite-state machine FSM finite-state automaton FSA automata finite automaton state machine model of computation abstract machine states inputs transition Taken from https://en.wikipedia.org/wiki/Finite-state_machine Hopefully that definition connects with what I talked about above with UI states. If not, donāt worryāāāa practical example is coming! As a small note, itās interesting to take note of that word in the description. In math and computer science, an automaton is an āabstract machineā which deals with computability. These form a hierarchy: automaton automata From: https://en.wikipedia.org/wiki/Automata_theory As you can see from the diagram, finite state machines occupy a higher tier of automata than mere combinational logic (booleans and if statements). Simply put, they provide you the language to describe something in a more precise way than you can with combinational logic alone. stateful We can put this theory into practice and use them with React āļø The <HardChoiceButton> Component A while back posted this tweet shortly after the Hawaiian missile scare: Wes Bos Iām going to use this component as inspiration and build something similar using . react-machinery The result will be a component called the and it will take a message to display, a number of seconds to countdown, and an action function to run as props. HardChoiceButton, If you want you can take a quick look at the finished example here before reading on for better context. The button starts in a state, and when a user presses the button, they enter the state. wait for input pending During the state a timer is ticking down from 5 (or whatever value we pass). At any time during this countdown, the user can press the button again to abort the operation, taking them to the state. pending aborted If they donāt press the button during , and the countdown makes it all the way to 0, then the action is executed and the button goes to the state. pending done We can represent the above using logic with the following state diagram: Bringing in react-machinery Letās start defining the class: HardChoiceButton As you can see, the StateMachine component exposed by take 4 props: the states array, functions to get/set the current state, and some data properties which Iāll get to in a second. You can wire up whatever data source you want to the and functionsāāātaking data from a redux store or mobx state treeāāābut this example just uses regular component state. react-machinery getCurrentState() setNewState() The states array contains objects that have a name, and in this case a function called render. The function here represents the component to render when in the state. This function receives the object as props, which allows us to display the āLaunch Missilesā message. render wait-for-input data The is not much good if it only has a single state though! Letās go ahead and fill in the rest of the states. HardChoiceButton A small note before we do: components that are associated with each state can be given in two ways. The first is through a function like above. This way follows the . The second way is to instead specify a property. This is not a function, but rather just a normal component. This style is a little more applicable if you have a react class component with itās own internal state. render render prop pattern component Complete state definition State definitions + two class components When we click the button in the state, we call . This is a special function that the component passes to along with the object. wait-for-input transitionTo(āpendingā) StateMachine render data There is another key inside called This is used to register the states that are allowed to be used with . Trying to transition to a state not registered will result in an error. validTransitions. transitionTo There is also a function that allows you to perform some side-effecty stuffāāāin this case making sure the timer is reset whenever we enter the state. This way we can ensure the timer always starts at 5. beforeRender wait-for-input When the pending state becomes active, it renders the component, a fairly straightforward class component that creates and destroys and interval, and renders the new button. Every second, the interval calls the function that was defined in the data of Pending decreaseTimeLeft() prop StateMachine. The mechanism to transition state to the state is a little different for though. Instead of calling , we can describe an automatic transitionāāāone that uses a function to determine whether to change state. These kind of transitions can be defined in states by the key. done pending transitionTo autoTransitions The rest of the states just use combinations of these different kinds of transition logic. Benefits So what benefits can you expect modelling components this this way? For starters, you know that you cannot arrive in a state that you did not explicitly define. Think about that for a minute because itās a pretty big idea. Having a state machine like this essentially eliminates a whole class of bugs that you have to test for. for sure Building on top of that, because youāre explicitly defining this data structure, you can use it to generate information about your components. Take the following function: That produces the following object (shown as JSON): You can use this information to generate state diagrams for your component. Itās literally self documenting. Now imagine you have logging enabled on a production site. You can easily write a state machine that logs every state change, providing you with breadcrumbs back to the source of any error. Lastly, changes to requirements in business logic can often be cleanly added. Letās say we needed to add a new behaviour when the user clicks the button with 1 second left on the clock. Instead of simply going to the state, we need to go to the state. aborted that-was-close Doesnāt take much to account for new requirements Conclusion If you find yourself developing bugs because of strange combinations of , considering implementing components using instead. You can start using them in React right now with (only 2kb gzipped!). State machines will help you model, reason about, and communicate the workings of your components more effectively. if-statements finite state machines react-machinery If you found this interesting please leave a š or two. Check out the code for React-Machinery on github and give me feedback there or on twitter @fstokesman .
Share Your Thoughts