Functional DOM programming

If you like functional programming, you probably hate using the DOM since it’s so mutative.

Wouldn’t it be great if we could create DOM nodes right from JavaScript?

React.renderComponent(
React.DOM.div(
null,
React.DOM.h1(null, 'Hello world!'),
React.DOM.p(null, 'This DOM was rendered from JS.')
),
document.body
);

(JSFiddle: http://jsfiddle.net/sb3x9/)

This makes it easy to interpolate (potentially unsafe) JS values into the DOM.

var text = 'This text was created in <strong>JS</strong> and rendered to the DOM.';
React.renderComponent(
React.DOM.div(
null,
React.DOM.h1(null, 'Hello world!'),
React.DOM.p(null, text)
),
document.body
);

(JSFiddle: http://jsfiddle.net/r9f6u/)

What would be really great is if we could write our DOM declaratively and avoid messy manual DOM mutation. Without destroying the DOM.

// Type your name into the text field to prove that
// the DOM is not being destroyed and rebuilt each
// time.
function render() {
React.renderComponent(
React.DOM.div(
null,
React.DOM.h1(null, ‘Hello world!’),
React.DOM.form(
null,
‘Your name is ‘,
React.DOM.input({
type: ‘text’,
placeholder: ‘Your name here’
})
),
React.DOM.p(null, ‘The time is ‘ + new Date())
),
document.body
);
}
setInterval(render, 1000);

(JSFiddle: http://jsfiddle.net/BLh7Q/)

If we can do that, then we can create loosely-coupled reusable components using simple JavaScript functions.

function zeroPad(s) {
s = s.toString();
if (s.length === 1) {
return ‘0' + s;
}
return s;
}
function clockComponent(time) {
return React.DOM.strong(
null,
time.getHours(),
‘:’,
zeroPad(time.getMinutes()),
‘:’,
zeroPad(time.getSeconds())
);
}

function render() {
React.renderComponent(
React.DOM.div(
null,
React.DOM.h1(null, ‘Hello world!’),
React.DOM.p(
null,
‘The time is ‘,
clockComponent(new Date())
)
),
document.body
);
}
setInterval(render, 1000);

(JSFiddle: http://jsfiddle.net/BeaRB/)

None of this is any good, though, if we can’t handle events.

var toggled = false;
function render() {
React.renderComponent(
React.DOM.div(
null,
React.DOM.h1({
className: toggled ? ‘red’ : ‘blue’
}, ‘Hello, world!’),
React.DOM.button({
onClick: function() {
toggled = !toggled;
render();
}
}, ‘Toggle color’)
),
document.body
);
}
render();

(JSFiddle: http://jsfiddle.net/LyNZM/)

Finally, what would a real app built in a functional style look like?

var todos = [];
function todoItemComponent(text) {
return React.DOM.li({
onClick: function() {
todos = todos.filter(function(candidateText) {
return candidateText !== text;
});
render();
}
}, text);
}
function todoListComponent() {
if (todos.length === 0) {
return React.DOM.p(null, ‘No TODOs on the list.’);
}

return React.DOM.ul(
null,
todos.map(todoItemComponent)
);
}
function addFormComponent() {
return React.DOM.form({
onSubmit: function(e) {
e.preventDefault();

var domNode = e.target.elements[0];
todos.push(domNode.value);
      // We *can* do this functionally but it’s outside
// the scope of this tutorial (there are a few
// tricks you need to do)
domNode.value = ‘’;
      render();
}
}, React.DOM.input({
placeholder: ‘New TODO item’
}), React.DOM.input({
type: ‘submit’,
value: ‘Add TODO’
}));
}
function render() {
React.renderComponent(
React.DOM.div(
null,
React.DOM.h1(null, ‘TODO list’),
todoListComponent(),
addFormComponent()
),
document.body
);
}
render();

(JSFiddle: http://jsfiddle.net/HsaGN/)


This is React.

It’s not about templates, or data binding, or DOM manipulation. It’s about using functional programming with a virtual DOM representation to build ambitious, high-performance apps with JavaScript.

Show your support

Clapping shows how much you appreciated Pete Hunt’s story.