By Facebook
Selectively re-render entire component on change
Simple functions that take in Props and State to render HTML.
Bindings
Observers
Templates
model.set('key', 'mad world');
f(state, props) = UI Fragment
f(props) = UI Fragment
Idempotency
Immutability
Testability
Bliss
Controllers
Directives
Templates
Global Event Listeners
Models
View Models
import React, { Component } from "react";
export class HelloWorld extends Component {
render() {
return ( <h1>Hello, world!</h1> );
}
}
React.render(<HelloWorld />, document.getElementById("myDiv"));
JSX
import React, { Component } from 'react';
export class Timer extends Component {
constructor() {
super(props);
this.state = {
secondsElapsed: 0
}
}
tick() {
this.setState({secondsElapsed: this.state.secondsElapsed + 1});
}
componentDidMount() {
this.interval = setInterval(this.tick, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<div>Seconds Elapsed: {this.state.secondsElapsed}</div>
);
}
});
React.render(<Timer />, mountNode);
Rerender
MOUNT
UNMOUNT
UPDATE
componentWillReceiveProps()
shouldComponentUpdate()
componentWillUpdate()
componentDidUpdate()
<MyComponent foo="bar">
// ES5
getInitialState: function() {
return { foo: 'bar' }
}
// ES6 constructor
this.state = { foo: 'bar' }
import React, { Component } from 'react';
export class FancyCheckbox extends Component {
render() {
let fancyClass = this.props.checked ? 'FancyChecked' : 'FancyUnchecked';
return (
<div className={fancyClass} onClick={this.props.onClick}>
{this.props.children}
</div>
);
}
});
React.render(
<FancyCheckbox checked={true} onClick={console.log.bind(console)}>
Hello world!
</FancyCheckbox>,
document.getElementById('example')
);
Props
import React, { Component } extends 'react';
export class FancyCheckbox extends Component {
render() {
let { checked, ...other } = this.props;
let fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
return (
<div {...other} className={fancyClass} />
);
}
}
React.render(
<FancyCheckbox checked={true} onClick={console.log.bind(console)}>
Hello world!
</FancyCheckbox>,
document.getElementById('example')
);
DESTRUCTURING
CONSUMED
// code..
render() {
var { checked, title, ...other } = this.props;
var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
var fancyTitle = checked ? 'X ' + title : 'O ' + title;
return (
<label>
<input {...other}
checked={checked}
className={fancyClass}
type="checkbox" // no matter what `other` is type will always be checkbox.
/>
{fancyTitle}
</label>
);
}
// code..
export class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {count: props.initialCount};
}
tick() {
this.setState({count: this.state.count + 1});
}
render() {
return (
<div onClick={this.tick.bind(this)}>
Clicks: {this.state.count}
</div>
);
}
}
Counter.propTypes = { initialCount: React.PropTypes.number };
isRequired
* Use only in Development
Motivation
Modification in real DOM tree evil
import React, { Component } from 'react';
export class Button extends Component {
constructor(props) {
super(props);
this.state = { liked: false };
}
_handleClick() {
this.setState({liked: !this.state.liked})
}
render() {
let text = this.state.liked ? 'like' : 'unlike';
return (
<p onClick={() => this._onClick()}>
You {text} this. Click to Toggle.
</p>
);
}
}
import React, { Component } from 'react';
export class Button extends Component {
constructor(props) {
super(props);
this.state = { liked: false };
this. _handleClick = this._handleClick.bind(this);
}
_handleClick() {
this.setState({liked: !this.state.liked})
}
render() {
let text = this.state.liked ? 'like' : 'unlike';
return (
React.DOM.p({ onClick: this._handleClick },
'You ', text, 'this. Click to Toggle'
)
);
}
}
// REACT API
// returns a reference to the Component
// callback gets called after rendering.
ReactComponent render(ReactElement element, DOMElement container, [function callback]);
Based on two assumptions
renderA: <div />
renderB: <span />
=> [removeNode <div />], [insertNode <span />]
renderA: <Header /> // Component
renderB: <Content /> // component
=> [removeNode <Header />], [insertNode <Content />]
2. Different DOM Nodes
renderA: <div id="before" />
renderB: <div id="after" />
=> [replaceAttribute id "after"]
renderA: <div style={{color: 'red'}} />
renderB: <div style={{fontWeight: 'bold'}} />
=> [removeStyle color], [addStyle font-weight 'bold']
2. Same Custom Components
// No mutation required.
renderA: <div><span>first</span></div>
renderB: <div><span>first</span><span>second</span></div>
=> [insertNode <span>second</span>]
// mutation required.
renderA: <div><span>first</span></div>
renderB: <div><span>second</span><span>first</span></div>
=> [replaceAttribute textContent 'second'], [insertNode <span>first</span>]
renderA: <div><span key="first">first</span></div>
renderB: <div><span key="second">second</span><span key="first">first</span></div>
=> [insertNode <span>second</span>]
var root = React.createElement('div');
React.render(root, document.getElementById('example'));
let root = <ul className="my-list">
<li>Text Content</li>
</ul>;
React.render(root, document.getElementById('example'));
var child = React.createElement('li', null, 'Text Content');
var root = React.createElement('ul', { className: 'my-list' }, child);
React.render(root, document.getElementById('example'));
properties
Children
Used as properties of ReactElements to represent children
Can be either:
import React, { Component } from 'react';
export class MyComponent extends Component{
render() {
...
}
};
let component = new MyComponent(props); // never do this
let element = React.createElement(MyComponent); // use this
var element = <MyComponent />; // using JSX
var component = React.render(element, document.getElementById('example'));
let componentA = React.render(<MyComponent />, document.getElementById('example'));
let componentB = React.render(<MyComponent />, document.getElementById('example'));
componentA === componentB; // true
function createFactory(type) {
return React.createElement.bind(null, type);
}
let div = React.createFactory('div');
let root = div({ className: 'my-div' });
React.render(root, document.getElementById('example'));
ReactJS is a JavaScript library for building UI
Flux is application architecture for building UI
- Wikipedia
- Flux website
NO Framework
Backbone: Pub - Sub
model.on('change:name', function() { ... })
Angular: 2-way data binding and $digest loop
$scope.name = ...
React: 1-way data flow
By @gaearon
The state of your whole application is stored in an object tree inside a single store.
The only way to mutate the state is to emit an action ( an object describing what happened )
To specify how the state tree is transformed by actions, write pure reducers.
_recipes = [];
function addRecipes(recipe){
_recipes.push(recipe);
}
let RecipeStore = Flux.createStore({
getRecipes: function(){
return _recipes;
}
}, function(payload){
if(payload.actionType === "ADD_RECIPE") {
addRecipes(payload.text);
RecipeStore.emitChange();
}
});
function recipes(initialRecipes = [], action) {
switch (action.type) {
case 'ADD_RECIPE':
return [..initialRecipes]
}
}
import { combineReducers, createStore } from 'redux';
let reducer = combineReducers({ recipes });
let store = createStore(reducer);
// store.getState() will return app state
// actions
store.dispatch({
type: 'ADD_RECIEPE',
text: 'xyz'
});
// use connect() to receive a dispatch function
// as a prop,and any state it needs from the
// global state.