User Interface
as a pure function
-
State machine
-
Magical Powers
-
Pure Function
-
Virtual DOM (pt. 2)
-
Immutability(pt. 2)
A pure function of an application state
inspired from React
Benefit of using a pure function for UI
- Works on top of immutability
- Works on top of virtual DOM
- We can save, load and undo the UI
Let's define a pure function
To be pure a function needs to meet two criteria:
- Evaluates the same result value given the same argument value(s)
- Evaluation of the result does not cause any semantically observable side effectÂ
A simple example
Let's take the toUpperCase method of the String object
var str = "uppercase";
str.toUpperCase() // <= UPPERCASE
str // <= uppercase
Let's try it with an actual UI
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:
This is how first variant works:
<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>
This is how second one does:
<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>
Think about scaling the first version
Think about scaling the second version
The complexity index
- O(N*M)
- O(N+M)
Magical Powers
// 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
User Interface as a pure function
By elismatic
User Interface as a pure function
- 693