The History of (JavaScript) State Management in 2019

Charlie Greenman
Jan 27, 2019 · 7 min read

I wanted to write this, because having a history of state management put’s into perspective why we need state management. It also put’s into perspective how much things change, and how important having a foundation in software is. In particular, to be aware of alternatives, and to help with learning new concepts. Jumping right in, jQuery was created a very long time ago, already back in 2006. Show, hide, remove, add, as well as element selectors, were already present in Version 1. Javascript had this capability as well if need be. However, no one really thought of it as state management.

Timeline of State Management in Javascript

State Management with jQuery

A classic component, I remember that was always created with jQuery, would be image sliders. In the more eloquent apps, they would use singleton classes,
perhaps even using prototypes if they knew what they were really doing. Variables would be cached by initialising once. Functions would be kept small. Everything including css, would have very unique nomenclature, using something like BEMCSS, for instance. Folder/file structure was important, but there wasn’t really anything like state management. Ironically, many smaller websites at this time were more performant in many ways. Why? Because, many intentionally kept them small, in order to do more.

Just for clarity sake, the following is a great example of how jQuery and Javascript “state management” would work(updated to use es6):

// _elem.js file
storeValues: [],
storeColors: [],
sassColorVariables: [],
lessColorVariables: []
// _grid.js file
updateGridColor: () => {
for(let x = 0; x < elem.s.columnCount; x++) {
for(let y = 0; y < elem.s.rowCount; y++) {
ctx.strokeStyle = `${elem.el.backgroundRed.value + 44}. ${elem.el.backgroundGreen.value + 44}. ${elem.el.backgroundBlue.value + 44}`;
ctx.strokeRect(x * elem.s.pixSize, y * elem.s.pixSize, elem.s.pixSize, elem.s.pixSize);
ctx.fillStyle = elem.el.backgroundHexColor.value;
ctx.fillRect(x * elem.s.pixSize + 1, y * elem.s.pixSize + 1, elem.s.pixSize - 2, elem.s.pixSize - 2);
}
}
for(let x = 0; x < elem.s.storeValues.length; x++){
ctx.fillStyle = elem.s.storeValues[x][2];
ctx.fillRect(parseFloat(elem.s.storeValues[x][0]) + 1, parseFloat(elem.s.storeValues[x][1]) + 1, elem.s.pixSize - 2, elem.s.pixSize - 2);
}
}

Above code taken from the codeIllustrator repo.

State Management with Backbone

Intro to Backbone.js Model View

Backbone applications to me were so funny, and still are. It literally looked
like a well architected jQuery app minus routing. Which now that I think about it, isn’t funny. Backbone was a big step up. Routing was a very nice touch that offered something like that out of the box. Ultimately, there really was no concept of state management with backbone either. However, I remember apps being performant, and unmanageable in many cases due to the bad architecture. A step up, of course from badly engineered jQuery applications. So, no state management at this point yet, still! However, using “model”, there was somewhat a way to do this, that was baked into best practices:

// note_model.js
“use strict”;
APP.NoteModel = Backbone.Model.extend({
// you can set any defaults you would like here
defaults: {
title: “”,
description: “”,
author: “”,
// just setting random number for id would set as primary key from server

id: _.random(0, 10000)
},
//…
// note_edit.js
save: function (event) {
event.stopPropagation();
event.preventDefault();
// update our model with values from the form
this.model.set({
title: this.$el.find(‘input[name=title]’).val(),
author: this.$el.find(‘input[name=author]’).val(),
description: this.$el.find(‘textarea[name=description]’).val()
});
//…

The model could beglobal, or per each component, and would be updated using the above syntax.

2015–2016 was a great year of performance, due to a growth spurt in browser capabilities. (The change log for 2015, is the last time you will see google chrome mentioning
performance in it’s logs for Chrome). Which between me and you is part of what enabled frameworks to become more prominent.

State Management with AngularJS

Controller, Service and Template Interacting with Each Other

AngularJS was fantastic because it offered two way binding out of the box. A lot of web applications needed/need that. It also came hand in hand with Jasmine unit testing, and event handling. Completely irrelevant to state management. However, because it introduced services, it really was the first framework to start boxing applications into, “this is what front end architecture should look like”, paving the way for state management.

Services, while mainly used for data, were also used different parts of the
application to interact with each other. Being that Angular applications were
Single Page Applications by default, this worked. State was synonymous with
services. If you wanted different components to know about each other in an efficient fashion, you would have a setter and getter for that service. The issue with this approach, is that there would be 4, or 5 services that would interact with each other, and it would cause serious issues. In addition, in many applications, old code/bad practices would use $scope in the code base, causing some serious performance issues. The following is what a sample service using a factory would look like:

var myApp = angular.module('myApp',[]);
myApp.factory('myService', function() {
var test = 5;
var obj = {
test : 5
}
return{
setTestVal: function(val){
test = val;
obj.test = val;
},
getTestVal: function(){
return test;
},
data : obj
}
});function MyCtrl($scope, myService) {
$scope.test = myService.getTestVal();
$scope.data = myService.data;
}
function SetCtrl($scope, myService){
$scope.newTestVal = '';
$scope.setTestVal = function(val){
myService.setTestVal(val)
}
}

State Management with React

React and Redux Architecture

React came around, and interested me at-least for two reasons. It offered
flexibility being a library and not a framework. Second, it was fast in
comparison to AngularJS. Flux came out, and was my first introduction to a
state management system. Redux came out 6 months after Flux already, so
admittedly, I only had a chance to work with Flux for a month, before we already started moving to Redux. Flux was a bit difficult, and during that month time, I remember my code reviews being rampant, with don’t do this, do that etc. Shortly after Flux, Redux came around, and for the first time it felt like a mature state management system came around. It was honestly the first time that I felt like I was doing something I hadn’t done before during my vanilla Javascript days.

// pixel-color-picker.js component
handlePixelColorChange(e){
const {dispatch} = this.props;
this.setState({pixelHex: e.target.value}, function(){
dispatch(PixelColor(this.state.pixelHex));
dispatch(PixelColorRGB(hexToRgb(this.state.pixelHex).r, hexToRgb(this.state.pixelHex).g, hexToRgb(this.state.pixelHex).b));
});
}
// control-panel.js actions
export function PixelColor(color){
return{
type: types.PIXEL\_COLOR,
pixelHex: color
}
}
// colorPicker.js reducer
case types.PIXEL\_COLOR:
return Object.assign({}, state, {
pixelHex: action.pixelHex || state.pixelHex
}
);

Code taken from the pixelLight Repo

Reactive State Management with React and Angular

Effects Flow Diagran

Around this time @ngrx/store came out, reactive programming became more popular. Within the context of state, this meant redux-observable for React, and @ngrx/store for Angular. For Angular, this meant that state is now cookie
cutter. For React and Angular, it meant that users have the ability to tie state into the rest of their application, primarily by means of using effects.

Observable.merge(
// Create observable map for when background hex changes, and use that
// value to update store for backgroundColor
this.changePixelColor$.map((value: any) => (
PixelColor(value)
)),
this.changePixelColorRGB$.map((value: any) => (
PixelColorRGB(value.pixelRed, value.pixelGreen,
value.pixelBlue)
))
)
.subscribe((action)=>{
store.dispatch(action)
})
}

Code taken from the angularPixel_illustrator repo

Hooks and Context with React + Vue

Replacing Redux with the New Context API

Where we are at currently, is that new waves are being made with regards to
state management. State is being baked into frameworks in ways that make it
more lightweight, and easier to deal with. Vue and React now have a feature
called hooks, and context. These allow an app to have state out of the box.
Redux + Redux Observable still have they’re place. There are times where state is necessary to allow components on different pages interact with each other. Other times, it can be a way of managing the data, to make sure the app is maintainable. If you see your app heading in the direction of the latter, Redux + Redux Observable is still recommended.

// theme-context.js// Make sure the shape of the default value passed to
// createContext matches the shape that the consumers expect!
export const ThemeContext = React.createContext({
theme: themes.dark,
toggleTheme: () => {},
});
// theme-toggler-button.jsimport {ThemeContext} from './theme-context';function ThemeTogglerButton() {
// The Theme Toggler Button receives not only the theme
// but also a toggleTheme function from the context
return (
<ThemeContext.Consumer>
{({theme, toggleTheme}) => (
<button
onClick={toggleTheme}
style={{backgroundColor: theme.background}}>
Toggle Theme
</button>
)}
</ThemeContext.Consumer>
);
}
export default ThemeTogglerButton;

Code taken from the React.js documentation

Final Words on State Management

I remember 5 years ago when all of the frameworks were coming out, there was a developer who told me that if you know what you are doing, really none of the frameworks are necessary. That being said, no one in their right mind, is going to create their own framework when they have it readily available. That is, unless your company has the agenda to make one. However, what is important, is to understand the internals, so that you can be much more valuable when it comes to performance, and maintainability of your project. I think that is obvious, but just wanted to bring it up.

Note: I did not include Elm, Ember.js, or Cycle.js. I think these are fantastic frameworks and deserve mention. However, from what I experienced working on enterprise applications in New York, these never made their way into my day to day, and therefore did not make their way into this timeline.

Razroo

UI Architecture

Charlie Greenman

Written by

Virtuous ruckus running amok, digitally.

Razroo

Razroo

UI Architecture

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade