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