React

Summary

  • What
  • Who
  • Why
  • How
  • Code examples
  • Some thougts

What

  • Library for creating user interfaces
  • Renders UI and responds to events
  • V in the MVC
  • Stack independent

Who

  • Born at Facebook Ads Org
  • Decoupled from Facebook stack to be used by Instagram
  • Open source

Why

  • Classic MVC
    • "View model" tightly couples controllers to templates
    • Templates separate technologies, not concerns
    • Developers are forced to separate application concerns in a bad way
    • Framework cannot know how to separate components - should be the developer

Why

  • Reacting to changes in the UI is hard
  • So much state and UI elements
  • Data changing
  • We all miss the 90's!

Why

  • Complexity increases with:
    • Number of developers
    • UI itself
  • Imagine the complexity of Facebook

How

  • Build components, not templates
    • Components know how to render themselves
    • Separation of concerns
    • Yes, we're talking about mixing markup and display logic
var CommentForm = React.createClass({
  handleSubmit: function(e) {
    e.preventDefault();
    var author = React.findDOMNode(this.refs.author).value.trim();
    var text = React.findDOMNode(this.refs.text).value.trim();
    if (!text || !author) {
      return;
    }
    this.props.onCommentSubmit({author: author, text: text});
    React.findDOMNode(this.refs.author).value = '';
    React.findDOMNode(this.refs.text).value = '';
    return;
  },
  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
    );
  }
});

How

  • Re-render on every update
    • When data changes, components are re-rendered
    • Easy and intuitive to the developer
  • But...
    • You can't just throw out the DOM!
    • Slow, flash effect, scroll position...

How

  • Virtual DOM
    • Makes re-render extremely fast
  • So, on every update
    • React builds a new virtual DOM subtree

    • Diffs it with the old one

    • Computes the minimal set of DOM mutations and puts them in a queue

    • And batch executes all updates

Virtual DOM

App

Virtual Dom

DOM

----------->

----------->

<-----------

<-----------

builds/modifies

builds/modifies

events

events

React key principles

  • Components, not templates
  • Re-render, don't mutate
  • Virtual DOM is simple and fast
<!-- index.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>Hello React</title>
    <script src="https://fb.me/react-0.13.3.js"></script>
    <script src="https://fb.me/JSXTransformer-0.13.3.js"></script>
  </head>
  <body>
    <div id="content"></div>
    <script type="text/jsx">
      // Your code here
    </script>
  </body>
</html>

Setup

Thinking in components

CommentBox

CommentList

Comment

Comment

CommentForm

var CommentBox = React.createClass({
  render: function() {
    return (
      <div className="commentBox">
        Hello, world! I am a CommentBox.
      </div>
    );
  }
});
React.render(
  <CommentBox />,
  document.getElementById('content')
);

Component

JSX is a JavaScript syntax extension that looks similar to XML.

You can use a simple JSX syntactic transform with React.

var CommentList = React.createClass({
  render: function() {
    return (
      <div className="commentList">
        Hello, world! I am a CommentList.
      </div>
    );
  }
});

var CommentForm = React.createClass({
  render: function() {
    return (
      <div className="commentForm">
        Hello, world! I am a CommentForm.
      </div>
    );
  }
});

Composing components

var CommentBox = React.createClass({
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList />
        <CommentForm />
      </div>
    );
  }
});

Composing components

var Comment = React.createClass({
  render: function() {
    return (
      <div className="comment">
        <h2 className="commentAuthor">
          {this.props.author}
        </h2>
        {this.props.children}
      </div>
    );
  }
});

Props

var CommentList = React.createClass({
  render: function() {
    return (
      <div className="commentList">
        <Comment author="Pete Hunt">This is one comment</Comment>
        <Comment author="Jordan Walke">This is *another* comment</Comment>
      </div>
    );
  }
});

Props

var CommentList = React.createClass({
  render: function() {
    var commentNodes = this.props.data.map(function (comment) {
      return (
        <Comment author={comment.author}>
          {comment.text}
        </Comment>
      );
    });
    return (
      <div className="commentList">
        {commentNodes}
      </div>
    );
  }
});

Props

Props

  • Components configuration, options if you may
  • Received from parent component, and immutable
  • Components are responsible for putting together the props of its child components
var CommentBox = React.createClass({
  getInitialState: function() {
    return {data: []};
  },
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm />
      </div>
    );
  }
});

State

var CommentBox = React.createClass({
  getInitialState: function() {
    return {data: []};
  },
  loadCommentsFromServer: function() {
    // Fetch data here
    this.setState({data: data});
  },
  componentDidMount: function() {
    this.loadCommentsFromServer();
    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
  },
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm />
      </div>
    );
  }
});

State

Thinking in components

CommentBox

CommentList

Comment

Comment

CommentForm

var CommentBox = React.createClass({
  getInitialState: function() {
    return {data: []};
  },
  loadCommentsFromServer: function() {
    // Fetch data here
    this.setState({data: data});
  },
  componentDidMount: function() {
    this.loadCommentsFromServer();
    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
  },
  handleCommentSubmit: function(comment) {
    // submit to the server and refresh the list
    this.setState({data: data});
  },
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
      </div>
    );
  }
});

Callbacks as props

var CommentForm = React.createClass({
  handleSubmit: function(e) {
    this.props.onCommentSubmit({author: author, text: text});
    return;
  },
  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
    );
  }
});

Callbacks as props

State

  • State starts with a default value when a componenent mounts
  • Suffers from mutations in time
  • Has no business fiddling with the state of its children
  • You could say the state is private

Some thoughts

  • New paradigm
  • Everyone in the team must be confortable
  • Difficult to integrate in an existing project
  • Spend all the necessary time designing the components

Useful links

  • https://www.youtube.com/watch?v=x7cQ3mrcKaY
  • https://youtu.be/KVZ-P-ZI6W4
  • https://facebook.github.io/react/docs/tutorial.html
  • https://facebook.github.io/react/docs/thinking-in-react.html
  • https://github.com/uberVU/react-guide/blob/master/props-vs-state.md

Thanks!