Introduction to React

@ccoenraets

Christophe Coenraets

Salesforce.com

Boston, MA

@ccoenraets

http://coenraets.org

https://github.com/ccoenraets

A library for creating user interfaces

Is it another case of ...

My MVC is better than your MVC

My MVVM is better than your MVC

My MVC is better than your MVVM

React challenges established best practices in traditional MV* frameworks

Traditional MV* Frameworks

Separation of Concerns

Model
Data
Controller
Display logic (JavaScript)
ModelView
Tailored Data
View
Templates (HTML + custom extensions)

Controller, ModelView, and View are coupled:
when you change one, you often have to change the others

TemplatesReact Components
Separation of ConcernsTechnology
(JS, HTML)
Responsibility
"Display UI"
SemanticNew concepts and micro-languages
(scope, directives, iterators)
HTML and JavaScript
ExpressivenessUnderpoweredFull power of JavaScript

Build components, not templates

Creating the UI Description

var child1 = React.createElement('li', null, 'First Text Content');
var child2 = React.createElement('li', null, 'Second Text Content');
var root = React.createElement('ul', { className: 'my-list' }, child1, child2);
React.render(root, document.getElementById('example'));

JSX

JSX

var Header = React.createClass({ render: function () { return ( <h1>Employee Directory</h1> ); } });

Traditional Performance Best Practices

But should the app developer be responsible for low-level DOM optimizations?

React

Re-render everything on every update

Sounds Expensive?

Virtual DOM

Re-render everything on every update:

  1. Create lightweight description of component UI
  2. Diff it with the old one
  3. Compute minimal set of changes to apply to the DOM
  4. Batch execute all updates

Virtual DOM Benefits

  1. Clean
    Clear, descriptive programming model
  2. Fast
    Optimized DOM updates and less reflows

Demos & Code

Creating Components

  1. Create the component using React.createClass()
  2. Implement the render() function
  3. Return the UI description

Creating a Component

var Header = React.createClass({ render: function () { return ( <h1>Employee Directory</h1> ); } });

Component Rendering

Composition

var HomePage = React.createClass({ render: function () { return ( <div> <Header /> <SearchBar /> <EmployeeList /> </div> ); } });

Data Flow

Parent-to-Child

Data Flow

Parent

var HomePage = React.createClass({ render: function () { return ( <div> <Header title="Employee Directory"/> <SearchBar/> <EmployeeList/> </div> ); } });

Data Flow

Child

var Header = React.createClass({ render: function () { return ( <h1>{this.props.title}</h1> ); } });

Inverse Data Flow

Child-to-Parent

Pass event handler has a property

Inverse Data Flow

Parent

var HomePage = React.createClass({ searchHandler:function(key) { alert('Search key: ' + key); }, render: function () { return ( <div> <Header text="Employee Directory"/> <SearchBar searchHandler={this.searchHandler}/> <EmployeeList/> </div> ); } });

Inverse Data Flow

Child

var SearchBar = React.createClass({ keyChange: function(event) { var searchKey = event.target.value; this.props.searchHandler(searchKey); }, render: function () { return ( <input type="search" onChange={this.keyChange}/> ); } });

State

Parent

var HomePage = React.createClass({ getInitialState: function() { return {employees: []} }, searchHandler: function(key) { this.props.service.findByName(key).then(function(result) { this.setState({searchKey: key, employees: result}); }.bind(this)); }, render: function () { return ( <div> <SearchBar searchHandler={this.searchHandler}/> <EmployeeList employees={this.state.employees}/> </div> ); } });

State

Child

var EmployeeList = React.createClass({ render: function () { var items = this.props.employees.map(function (employee) { return ( <EmployeeListItem key={employee.id} employee={employee}/> ); }); return ( <ul> {items} </ul> ); } });

The key attribute is used to uniquely identify an instance of a component (useful in the diff process)

State

Nested Child

var EmployeeListItem = React.createClass({ render: function () { return ( <li> <a href={"#employees/" + this.props.employee.id}> {this.props.employee.firstName} {this.props.employee.lastName} </a> </li> ); } });

Resources

Thank You!

@ccoenraets