State management in Velo
Thanks to the Wix editor, when working with Velo you don’t need to deal with html/css when developing UI. Instead you get a full blown WYSIWYG editor where you can create the UI for your application. Then all that’s left to do is write the application logic, which is really what we want to focus on when developing applications.
Most Velo examples you’ll see today that connect application logic to the view are similar to old style jQuery applications. You bind to event handler of UI elements and in response to those events you run some logic which updates other UI elements with the result.
jQuery style
Let’s take an example. Say you have a view with a text element (#counter) which displays a counter and two button elements (#increment & #decrement) which increment or decrement that counter.
The Velo code which implements that logic will be something like:
This is a coding style that professional frontend developers cringe when they encounter since it reminds them the old jQuery days when we explicitly updated the UI with the effect of each interaction.
In order to understand why this is a bad pattern, let’s try to complicate the example a bit. Let’s say we also have another text element (#counter2) With it’s own increment/decrement buttons. This time we will also use the opportunity to do a small refactor. The logic implementation for this will be something like:
As you can see , in this pattern after we update some state (counter/counter2), and then we go and updated the relevant UI which should be affected by that state change. So if for example we add an additional text item calculating the sum of the two counters, we update it in all places:
Whoops! Did you see the bug? I forgot to call renderSum() also when #increment2 is clicked… Well, this is what happens when you wire UI and state manually. This only gets worse as the application gets more complicated and as behavior of the application change as you add more features.
See for example this todo list application, written in Velo using the jQuery pattern: https://shahata5.wixsite.com/velo-jquery
We have two bugs there:
- If you check the checkbox next to the todo item which marks it as done, the todo description gets strikethrough decoration, which is the expected behavior. But if you check the top checkbox which marks all todo items as done, we forgot to update the to item description with the strikethrough.
- If you check the checkbox next to the todo item which marks it as done, the “items left” counter at the left bottom is updated with the number of remaining items. But if we delete an uncompleted todo item using the delete button, we forgot to update the “items left” counter.
Those are annoying and hard to catch bugs. Every jQuery application was full of them and it made maintaining the code base of jQuery applications complete hell.
You can also play with the real app. Just open the velo-jquery example in the Wix editor (turn on dev mode from the top menu in order to see the code).
And then came data binding
Data binding is a pretty neat concept where you no longer need to explicitly update the UI when the state changes. Instead, you define what piece of state goes in each UI element using some framework. Then, when you update the state in that framework, it automatically updates the UI with the relevant changes. Since the framework knows what UI element needs what piece of state, it can make sure to update only the UI elements that care about the part of state that was updated.
So what are those framework? Actually there’s tons of them. The first widely used such framework was actually Angular, but Angular was much more than just a data binding or state management framework. It was very coupled with many more concerns and most importantly it was coupled with how the UI is rendered, which is obviously a problem for us since we want to render the UI with Velo.
But then something nice happened. React came out and put on its flag to only be opinionated about how UI is rendered, the rest was open for extensibility. Soon, a new generation of state management frameworks appeared which only gave you a method to manage your state and only needed small adapters to bind the state into the React based application view. Later versions of Angular also allowed to easily use such state management instead of the built-in state management that came with Angular.
This was great since essentially you can write almost all of your application logic without really caring what framework you would use for rendering the UI. It means that if you used such state management framework, you could pretty easily move your application logic from React to Angular or even some other future framework that might come out (like Velo!) and the only thing that would change is the wiring of the state to the UI.
In this article we will look into my favorite state management framework (MobX) and see how you can easily connect it to a Velo application. This also means you can easily take any MobX based application and migrate it from React to Velo!
In order to use MobX you’ll need to install it in your Velo application.
MobX
In MobX the main concept is that you bind to some derived state and MobX knows to identify automatically your state dependencies and automatically creates an observable for it and runs your binding again only when the state that you depend on changes. Let’s see MobX in action with our two counters and sum example:
That’s it. The cool thing about MobX is that it will run the autorun methods only when the state that they use has changed. So when we update counter the second autorun doesn’t run, and when we update counter2 the first autorun doesn’t run. The third autorun will run in both cases since it depends on sum which depends both on counter and counter2.
Note that instead of having that sum getter function in the observable, we could have done something like:
autorun(() => $w('#sum').text = `${state.counter+state.counter2}`);
This would have worked just the same and we wouldn’t have needed the getter. However, as I mentioned before — it is wise to separate the logic from the view, because then you can easily reuse your state when changing the view technology. I recommend to always do all calculations in the observable state using getters and leave the view as dumb as possible.
Pretty simple, right? Let’s complicate it a bit. Let’s make a simplified todo list. Now we have a text input (#input) and an add button (#add) and we have a repeater (#repeater) which will display the items that we added. For each item in the repeater we’ll have a text element displaying the description (#description) and a delete button to remove it from the list (#remove).
This will look something like this:
Now, this is interesting. What we do here is that we bind an array to the data property of the repeater element (#repeater). As you can see, the initial state of that array are three todo items, each item has a _id property and a description property. The _id is a unique identifier mandatory for any repeater item as described in Velo docs.
The second thing interesting here is the repeater’s onItemReady which we use in order to bind elements inside the repeater to our state. Inside onItemReady we do all of the binding necessary using the $item selector.
This is actually almost everything you need to know in order to use MobX in a Velo application, except we have one bug in the above code. The thing is, that the calls to autorun are adding observers for each item in the repeater, but we don’t clean up those observers when the repeater items gets removed. This might result in memory leaks and also in exceptions when state get changed.
We fix this by putting all of the autorun return values (which are actually unsubscribe methods) into an array and invoking them in onItemRemoved when the the item gets removed.
In our case we have only one autorun, but usually you’ll have more, so an array is needed. This is also very visible in the live example below.
For a live example of a more complicated todo list open the velo-mobx example in the Wix editor (turn on dev mode from the top menu in order to see the code).
As you’ll see in the live example, MobX is also very helpful when hiding and showing an elements. Let’s say you have some boolean state that says if some element should be visible or not. In MobX you would simply do:
autorun(() => state.shouldShow ?
$w('#element').show() : $w('#element').hide());
Redux
Another very popular state management framework (which I openly detest) is Redux. I don’t recommend using it for a new application, but if you have an existing Redux application and want to move it to Velo without rewriting all you state logic then this is possible using a nice helper I created called @wix/velo-redux.
For a live example of the todo list using Redux open the velo-redux example in the Wix editor (turn on dev mode from the top menu in order to see the code).