React
A new approach to the UI
Text
About Me...
@Garry Yao
- CKEditor
- Teambition
- Englishtown
Server rendering
- Server renders the HTML
- jQuery "splice" in browser
- Ajax "decorate" data submission
Client rendering
- Server emits JSON
- single page app in MVC
- Handlebars aka. "templates" renders the HTML
State Of Art
Life is hard...because
- DOM manipulation is hard
- Data binding is hard
- Event handling is hard
- Manage states is hard
- Unit testing is hard
Developers can hardly resists to a hard life,
which spawn BUG...
Life is especially hard with...
Template
- separate technologies, not really concerns
- view models tightly coupled to template
- often lead to unnecessary re-rendering
- underpowered primitive abstractions like {{>}} and {{#each}}
Let's start to make change from...
reinventing
"template"
- Utilize the already familiarised syntax - like JavaScript!
- Access JS variable directly from within your markup - like closure!
- Produce something lightweight rather raw DOM - like fragments!
Visiting JSX
The Reactive markup language
Text
var myDivElement = <div>foo</div>;
React.render(myDivElement, mountNode);
Wait...what the heck is that XML?
JSX is a JavaScript syntax extension that looks similar to XML, think of E4X
JSX is your dev syntax
var myDivElement = <div className="foo">
<input type="text" value="JSX" />
</div>;
React.render(myDivElement, mountNode);
var myDivElement = React.createElement("div",
{className: "foo"},
React.createElement("input",
{type: "text", value: "JSX"})
);
React.render(myDivElement, mountNode);
it compiles to JS
The only syntax you need
to remember in JSX is...
{}
var isDisabled = true;
React.render(
<button disabled={isDisabled}>Submit</button>, mountNode);
var isDisabled = true;
React.render(React.createElement("button",
{disabled: isDisabled}, "Submit"), mountNode);
Attribute Expression
Children Expression
React.render(<input type="text" value={isFoo? 'foo' : 'bar'} />, mountNode);
React.render(<select>{
items.map(function(item){
return <option>{item.value}</option>;
})
}</select>, mountNode);
Combine
The accessibility of HTML
and the power of JavaScript
And...Custom Element
var Hello = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
React.render(<Hello name="John" />, document.body);
DOM Elements and SVG Element
a abbr address area article aside audio b base bdi bdo big blockquote body br
button canvas caption cite code col colgroup data datalist dd del details dfn
dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5
h6 head header hr html i iframe img input ins kbd keygen label legend li link
main map mark menu menuitem meta meter nav noscript object ol optgroup option
output p param picture pre progress q rp rt ruby s samp script section select
small source span strong style sub summary sup table tbody td textarea tfoot th
thead time title tr track u ul var video wbr
circle defs ellipse g line linearGradient mask path pattern polygon polyline
radialGradient rect stop svg text tspan
a React Component that
implements the "render" method
- this.states
- this.props
Custom Element in React is...
with the simplest state management
- this.setState
- this.setProps
and intuitive event handlers
A React component portfolio
var LikeButton = React.createClass({
getInitialState: function() {
return {liked: false};
},
handleClick: function(event) {
this.setState({liked: !this.state.liked});
},
render: function() {
var text = this.state.liked ? 'like' : 'haven\'t liked';
return (
<p onClick={this.handleClick}>
You {text} this. Click to toggle.
</p>
);
}
});
React.render(<LikeButton />, mountNode);
Use component to separate concerns
var TodoList = React.createClass({
render: function() {
var createItem = function(itemText) {
return <li>{itemText}</li>;
};
return <ul>{this.props.items.map(createItem)}</ul>;
}
});
var TodoApp = React.createClass({
getInitialState: function() {
return {items: [], text: ''};
},
handleSubmit: function(e) {
...
},
render: function() {
return (
<div>
<h3>TODO</h3>
<TodoList items={this.state.items} />
<form onSubmit={this.handleSubmit}>
<input value={this.state.text} />
<button>{'Add #' + (this.state.items.length + 1)}</button>
</form>
</div>
);
}
});
React.render(<TodoApp />, mountNode);
Life is hard when there are...
So many states!
- DOM mutations
- Data models mutations
- Styles mutations
- User inputs
KVO (key-value-observation) is like HELL
- To many computed values
- No single root of source
- Translate the "delta" to DOM is tricky
- Unaffordable man-month
In 90s it was easier
Just refresh the page!
What would makes it
easier for now?
How about just re-render the component?
React component re-renders itself for
states and props change
var Timer = React.createClass({
getInitialState: function() {
return {secondsElapsed: 0};
},
tick: function() {
this.setState({secondsElapsed: this.state.secondsElapsed + 1});
},
componentDidMount: function() {
this.interval = setInterval(this.tick, 1000);
},
componentWillUnmount: function() {
clearInterval(this.interval);
},
render: function() {
return (
<div>Seconds Elapsed: {this.state.secondsElapsed}</div>
);
}
});
React.render(<Timer />, mountNode);
Describe the UI from states, not DOM
Every moment your UI is guaranteed to be consistent and update-to-date
Re-render the entire component,
you are kidding me?
- Can you guarantee performance?
- how about scrolling and focus state?
- how about UI flickring?
Virtual DOM
The secret to rule them all!
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
React.render(<HelloMessage name="John" />, mountNode);
var HelloMessage = React.createClass({displayName: 'HelloMessage',
render: function() {
return React.createElement("div", null, "Hello ", this.props.name);
}
});
React.render(React.createElement(HelloMessage, {name: "John"}), mountNode);
Virtual DOM
The secret to rule them all!
- Render returns a new virtual DOM Tree
- diffs it with the old one
- computes the minimal set of DOM mutations required and put them in queue
- batch apply the mutations to only concerned DOM nodes
It's just fast still
It's just fast still
In effect, benchmark doesn't really matter if each of the DOM mutation can fit into
one RequestAnimationFrame
More than this...
- Testability for free
- No more jQuery splicing
- A lot transition/animation friendly
- Rendering on the server-side
- Automatic event delegation
Build with the full power of JavaScript, not a crippled template language
Q & A
Text
React - A new approach to UI
By Garry Yao
React - A new approach to UI
- 2,083