Last active
September 21, 2024 23:47
-
-
Save dbisso/d41881f5ed9b55ace73dbb0da6480bd2 to your computer and use it in GitHub Desktop.
Simple state management in vanilla JS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function State() { | |
this.actions = {}; | |
this.subscriptions = []; | |
this.history = []; | |
} | |
State.prototype.subscribe = function(element, action, callback) { | |
this.subscriptions[action] = this.subscriptions[action] || []; | |
this.subscriptions[action].push(function(data) { | |
callback.apply(element, data); | |
}); | |
} | |
State.prototype.dispatch = function(action, data) { | |
data = data || []; | |
// Store history of actions (not strictly neccessary) | |
this.history.push([action, data]); | |
// Call action reducers | |
if ("function" === typeof this[action]) { | |
this[action].apply(this, data); | |
} | |
// Add the action and state as final arguments | |
data.push(action); | |
data.push(this); | |
// Call subscribers | |
this.subscriptions[action] = this.subscriptions[action] || []; | |
this.subscriptions[action].forEach( | |
function(subscription) { | |
subscription(data); | |
} | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.done { | |
text-decoration: line-through; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<form id="addToDo"><input id="description" type="text"><button id="add">Add</button></form> | |
<ul id="todos"></ul> | |
<button id="removeAll">Remove All</button> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Application | |
var store = new State(); | |
// Define default state | |
store.todos = []; | |
// Define 'reducer' methods. Alter the state in response to actions | |
store.addTodo = function(description) { | |
this.todos.push(description); | |
} | |
store.removeTodo = function(index) { | |
this.todos.splice(index,1); | |
} | |
store.removeAll = function() { | |
this.todos = []; | |
} | |
// Get an element | |
var todos = document.getElementById("todos"); | |
// Subscribe the element to actions | |
// Callback is called with subscriber elements as context | |
store.subscribe(todos, "addTodo", function(description, action, store) { | |
// We can do what we like here. Update the DOM using vanilla | |
// JS or jQuery or whatever. | |
// We could even dispatch other actions | |
var item = document.createElement('li'); | |
var checkBox = document.createElement('input'); | |
checkBox.setAttribute('type', 'checkbox'); | |
item.addEventListener('change', function(event) { | |
store.dispatch( | |
"todoCompletion", | |
[event.target.checked, Number(item.getAttribute('data-key'))] | |
); | |
}); | |
item.textContent = description; | |
item.appendChild(checkBox); | |
item.setAttribute('data-key', store.todos.length - 1); | |
this.appendChild(item); | |
}); | |
store.subscribe(todos, "todoCompletion", function(isDone, index, action) { | |
this | |
.children[index] | |
.classList[isDone ? 'add': 'remove']('done'); | |
}); | |
store.subscribe(todos, "removeTodo", function(index) { | |
this.removeChild(this.querySelectorAll('li')[index]); | |
this.querySelectorAll('li').forEach(function(element, index) { | |
element.setAttribute('data-key', index); | |
}) | |
}); | |
store.subscribe(todos, "removeAll", function() { | |
this.querySelectorAll('li').forEach(function(element) { | |
this.removeChild(element); | |
}.bind(this)); | |
}); | |
store.dispatch("addTodo", ["do a thing"]); | |
store.dispatch("addTodo", ["do another thing"]); | |
store.dispatch("addTodo", ["do a thing"]); | |
store.dispatch("removeTodo", [0]); | |
document.getElementById("addToDo").addEventListener("submit", function(event) { | |
event.preventDefault(); | |
var description = document.getElementById("description").value; | |
store.dispatch("addTodo", [description]); | |
document.getElementById("description").value = null; | |
}); | |
document.getElementById("removeAll").addEventListener("click", function() { | |
store.dispatch("removeAll"); | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment