Skip to content
jamieonkeys.dev

Structuring JavaScript code

Managing state within a basic module pattern

Even if your web app is not at Facebook scale, you should probably still use a framework like Svelte or React to help you manage state. Even in an app of moderate complexity managing state can get confusing and bugs are apt to creep in. Over the years I’ve built some moderately complex web apps with either vanilla JS or jQuery, and while I’ve found it to be quite possible to manage state without the help of a framework, it’s not scalable. So I’m trying to move to using React or one of the lighter-weight implementations thereof.

Meantime, however, I have a couple of side projects in active development which manage state the old-fashioned way. Which is to say… manually. In some ways it’s actually easier to manage state manually. You don’t need to worry about learning a framework’s particular implementation of state management, and — in the case of a large framework — load a whole lot of superflous code at runtime. Just write to and read from a state object. Simple enough.

The approach I’ve taken is not innovative. Hell, it’s not even basic pub/sub. But for small-scale apps and assorted functionality on everyday websites I’ve found it works well, and is hopefully quickly understood by other developers who may work on the code after you.

Basic JavaScript module pattern permalink

Here’s the module pattern I use. It has a cfg object, a state object, an addHandlers() function and an init() function. It probably looks familiar.

/**
* @name MY_MODULE
* @author Jamie Smith
* @description Basic JavaScript module template with config and state objects, and private and public functions
*/


const MY_MODULE = (function () {

'use strict';

const cfg = {
foo: 'bar'
};

const state = {
init: false
};

function init() {
// ⋯
addHandlers();
state.init = true;
}

function addHandlers() {
// ⋯
}

function getState(property = null) {
if (property)
console.log(property, state[property]);
else
console.log(state);
}

function privateFnc() {
// ⋯
}

function publicFnc() {
privateFnc();
}

return {
init: init,
getState: getState,
publicFnc: publicFnc
};
})();

You could also add a sub-module, say for helper functions:

// (Note that this sub-module's methods will be publicly callable)
MY_MODULE.Utils = (function () {

'use strict';

// Example helper function
function helperFunction(value) {
if (value)
return `${value}-amended`;

return null;
}

return {
helperFunction: helperFunction
};
})();

You can call a submodule method from the main module using the this keyword, for example this.Utils.helperFunction().

The main module init() method can be called on load:

<script defer src="MY_MODULE.js" onload="MY_MODULE.init()"></script>

or:

<script defer src="MY_MODULE.js"></script>

<script>
window.addEventListener('DOMContentLoaded', () => {
MY_MODULE.init();
});
</script>

That’s it. If you wanted to make it even simpler you could just return the state object alongside init() etc. instead of using a ‘getter’ function. (The getter function just means that a savvy user couldn’t update the state object themselves by doing a MY_MODULE.state.init = 'derp', say, in the browser console.)

For a real-world example of this module pattern, see the state object in the app.js file on GitHub for my Scots language dictionary app scots.app.