Horváth, Győző
senior lecturer
horvath.gyozo@inf.elte.hu
Financed from the financial support ELTE won from the Higher Education Restructuring Fund of the Hungarian Government
View (and DOM) abstraction
Tools and code
npm install --save react react-dom
browserify -t babelify main.js -o bundle.js
<!doctype html><title>React</title>
<div id="container"></div>
<script src="dist/bundle.js"></script>
// main.js
var React = require('react');
var ReactDOM = require('react-dom');
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('container')
);
var TodoList = React.createClass({
render: function() {
var createItem = function(itemText, index) {
return <li key={index + itemText}>{itemText}</li>;
};
return <ul>{this.props.items.map(createItem)}</ul>;
}
});
var TodoApp = React.createClass({
getInitialState: function() {
return {items: [], text: ''};
},
onChange: function(e) {
this.setState({text: e.target.value});
},
handleSubmit: function(e) {
e.preventDefault();
var nextItems = this.state.items.concat([this.state.text]);
var nextText = '';
this.setState({items: nextItems, text: nextText});
},
render: function() {
return (
<div>
<h3>TODO</h3>
<TodoList items={this.state.items} />
<form onSubmit={this.handleSubmit}>
<input onChange={this.onChange} value={this.state.text} />
<button>{'Add #' + (this.state.items.length + 1)}</button>
</form>
</div>
);
}
});
Source --------------------------
Formerly these were separated:
But they belong together.
Former approach separated technologies, not concerns.
var TodoApp = React.createClass({
getInitialState: function() {
return {items: [], text: ''};
},
onChange: function(e) {
this.setState({text: e.target.value});
},
handleSubmit: function(e) {
e.preventDefault();
var nextItems = this.state.items.concat([this.state.text]);
var nextText = '';
this.setState({items: nextItems, text: nextText});
},
render: function() {
return (
<div>
<h3>TODO</h3>
<TodoList items={this.state.items} />
<form onSubmit={this.handleSubmit}>
<input onChange={this.onChange} value={this.state.text} />
<button>{'Add #' + (this.state.items.length + 1)}</button>
</form>
</div>
);
}
});
JavaScript:
ReactDOM.render(
React.createElement('h1', null, 'Hello, world!'),
document.getElementById('example')
);
JSX: alternate format (via Babel)
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
ES5:
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
Hello, world! I am a CommentBox.
</div>
);
}
});
ReactDOM.render(
<CommentBox />,
document.getElementById('example')
);
ES6:
class HelloMessage extends React.Component {
render() {
return <div>Hello world!</div>;
}
}
ReactDOM.render(<HelloMessage />, mountNode);
Data coming from outside of a component
this.props
class HelloMessage extends React.Component {
render() {
return <div>Hello {this.props.name}</div>;
}
}
ReactDOM.render(<HelloMessage name="Győző" />, mountNode);
Inner data
this.state
, this.setState()
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>
);
}
});
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>
);
}
});
getDOMNode()
ReactDOM.findDOMNode()
getInitialState()
componentWillMount()
componentDidMount()
componentWillReceiveProps(object nextProps)
shouldComponentUpdate(object nextProps, object nextState)
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)
componentWillUnmount()
key
: identifying DOM nodesref
: accessing DOM nodesNot modifying, re-rendering!
Re-render the whole component hierarchy on every data change.
Like PHP.
How can this be effective?
Decomposing the UI to components
Writing a static version
render()
methodsIdentifying a minimal UI state
props
: not stateDetermining the location of the state
getInitialState()
Data Down, Actions Up
var router = (function () {
"use strict";
var routes = [];
function addRoute(route, handler) {
routes.push({parts: route.split('/'), handler: handler});
}
function load(route) {
window.location.hash = route;
}
function start() {
var path = window.location.hash.substr(1),
parts = path.split('/'),
partsLength = parts.length;
for (var i = 0; i < routes.length; i++) {
var route = routes[i];
if (route.parts.length === partsLength) {
var params = [];
for (var j = 0; j < partsLength; j++) {
if (route.parts[j].substr(0, 1) === ':') {
params.push(parts[j]);
} else if (route.parts[j] !== parts[j]) {
break;
}
}
if (j === partsLength) {
route.handler.apply(undefined, params);
return;
}
}
}
}
window.onhashchange = start;
return {
addRoute: addRoute,
load: load,
start: start
};
}());
var App = React.createClass({
getInitialState: function() {
return {
page: null
}
},
componentDidMount: function() {
var self = this;
router.addRoute('', function() {
self.setState({page: <HomePage />});
});
router.addRoute('some/:id', function(id) {
self.setState({page: <SomePage />});
});
router.start();
},
render: function() {
return this.state.page;
}
});