Organizing around State

Joe Gregorio

This is L-Systems with Redux and StateReflector, but now with more organization around updating the state and around efficiently updating the DOM to changes in the state. That is, a simple app for drawing L-Systems, where making changes to the parameters (Length, Angle) is stored in the URL fragment identifier, thus creating a permalink for any selections a user makes. The state of the page is kept in a Redux state store and we use StateTools.getDelta() to store that changing state in the URL fragment, and also pull the state out of the URL and push it into the state when the URL changes.

The old render() function in our previous iteration was inefficent, every time 'state' changed all the elements were updated, even if the new value wasn't different from the old value.

To make this more efficient we can leverage (the newly renamed StateReflector to StateTools) StateTools.getDelta(), which returns the differences between the old state and the new state, so we only have to update elements that have changed. Similarly on the side of updating the state, we can consolidate some code around responding to events.

The markup for the page is straightforward:

And the JS is now much more compact also, coming in at just 73 lines of code:

What makes the main code so compact is the use of Redux for state management, and Binder, which is a small class for mapping state changes to and from HTML elements:

Binder is able to work because of some of the uniformity in how native HTML elements work, in particular that events are only generated via external stimuli. That is, merely changing the state of an element doesn't generate an event, for example, changing the checked value of a checkbox via the DOM does not generate an 'input' or 'changed' event.

This means that we should never encounter an infinite cascade of events. If an element generates an event and that changes the state, the new state will then be reflected in the elements, but since no new events are generted then the update cycle stops there. The general principles of not generating events on DOM changes, and announcing changes in state via events, are ones that should carry over when creating our own Custom Elements, which we'll get to in a later installment.

In general the code is fairly simplistic, I've only coded the happy-path, and since our 'StateTools.getDelta' algorithm is crude we can't really handle complex state objects, but there are plenty of other opensouce object diffing libraries that can be used to replace the simple version used here. OTOH, there is enough code there to prove out the idea, that building these one and two way bindings using state objects is not only feasible, but it dramatically improves the code and makes it easier to reason about the behavior of the system.

comments powered by Disqus