State machine
Magical Powers
Pure Function
Virtual DOM (pt. 2)
Immutability(pt. 2)
To be pure a function needs to meet two criteria:
Let's take the toUpperCase method of the String object
var str = "uppercase";
str.toUpperCase() // <= UPPERCASE
str // <= uppercase
If we have this...
<span id="counter">0</span>
<input id="color" type="color"></input>
<button id="increment"></button>
<script>
$('#color').on('click', function () {
$('#colored-counter').css('color', this.value);
})
$('#increment').on('click', function () {
var oldValue = $('#counter').html();
var newValue = 1 + Number(oldValue);
$('#counter').html(newValue);
})
</script>
<span id="counter">0</span>
<input id="color"></input>
<button id="increment"></button>
<script>
var state = {color: '', value: 0};
function updateUI() {
$('#counter').css('color', state.color);
$('#counter').html(state.value);
}
$('#color').on('keyup', function () {
state.color = this.value;
updateUI();
})
$('#increment').on('click', function () {
state.value++;
updateUI();
})
</script>
...it could be written as:
<span id="counter">0</span>
<input id="color"></input>
<button id="increment"></button>
<script>
$('#color').on('keyup', function () {
$('#counter').css('color', this.value);
})
$('#increment').on('click', function () {
var oldValue = $('#counter').html();
var newValue = 1 + Number(oldValue);
$('#counter').html(newValue);
})
</script>
<span id="counter">0</span>
<input id="color"></input>
<button id="increment"></button>
<script>
var state = {color: '', value: 0};
function updateUI() {
$('#counter').css('color', state.color);
$('#counter').html(state.value);
}
$('#color').on('keyup', function () {
state.color = this.value;
updateUI();
})
$('#increment').on('click', function () {
state.value++;
updateUI();
})
</script>
// save
var cannedState = deepcopy(state);
// load
state = cannedState;
updateUI();
<span id="time-pos"></span>
<button id="back">Back</button>
<button id="next">Next</button>
<script>
var time = {history: [], pos: 0};
function updateTimeUI() {
$('#time-pos').html('Position ' + time.pos + ' of ' + time.history.length);
}
function saveState() {
time.history.push(deepcopy(state));
time.pos++;
updateTimeUI();
}
$('#back').on('click', function () {
// Move history pointer
time.pos--;
updateTimeUI();
// Load historic state
state = deepcopy(time.history[time.pos]);
updateUI();
})
$('#next').on('click', function () {
time.pos++;
// ... same
})
// ...
function updateUI() {
// Save state to history on every change
saveState();
// ... continue as usual
}
</script>
<div id="ui">
<span id="count">2</span>
<ul>
<li>hi</li>
<li>there</li>
</ul>
<button id="add"></button>
</div>
<script>
var state = {items: ['hi', 'there']}
function updateUI() {
$('#count').html(state.items.length);
// Compare ul.childNodes to state.items and make updates
// ...
}
$('ul').on('click', 'li', function () {
state.items.splice($(this).index(), 1);
updateUI();
})
$('#add').on('click', function () {
state.items.push(getNextString());
updateUI();
})
</script>
Impure Function version
<div id="ui">
<span id="count">2</span>
<ul>
<li>hi</li>
<li>there</li>
</ul>
<button id="add"></button>
</div>
<script>
var state = {items: ['hi', 'there']}
function render(state) {
var span = '<span id="count">' + state.items.length + '</span>';
var lis = state.items.map(function (item) {
return '<li>' + item + '</li>';
});
return span + '<ul>' + lis.join('') + '</ul>'
}
function updateUI() {
$('#ui').html(render(state));
}
$('ul').on('click', 'li', function () {
state.items.splice($(this).index(), 1);
updateUI();
})
$('#add').on('click', function () {
state.items.push(getNextString());
updateUI();
})
</script>
Pure Function version