SlideShare a Scribd company logo
ReactJS
for Programmers
by Dr. David Rodenas
Origin
2014
FB about Web
3
https://youtu.be/nYkdrAPrdcw?t=10m20s
FB about MVC
4
“MVC works pretty well
for small applications…
but it doesn’t make room
for new features.”
“Flux is a single direction data flow,
that avoids all the arrows
going on all directions
what makes really
hard to understand the system.”
FB about Chat
5
“Let’s see a real good example: FB chat”
“How we get to the point, so we were annoying our
users so much the just they wanted us to fix chat?”
“The problems here were:
• The code has no structure
• It was very imperative, that makes it fragile
• It loose a lot of the original intend behind it, its hard to tell what it tries [to do]
• Add more features only gets this code larger
• We had our most annoying chat bug happen over and over
• We were always fixing some pretty good edge case, the whole system was fragile
• …
• This code becomes more fragile with the time.
• No member of the team wanted to touch it, they wanted to jump to any other bug.”
FB about Rendering
6
“Imperative Rendering”
“If renders all each time
the screen flickers”
“We wanted always render all, no matter what”
“Here is where React comes in.”
FB & Virtual DOM
7
ReactJS
Prerequisite
9
Install React Developer Tools
Basics
Hello World
<!-- hello-world.html -->
<div id="root"></div>
// hello-world.js
const virtualDom = React.createElement(
'h1', null, 'Hello, world!'
);
ReactDOM.render(
virtualDom,
document.getElementById('root')
);
11
Hello World
<!-- hello-world.html -->
<div id="root"></div>
// hello-world.jsx
const virtualDom = <h1>Hello, world!</h1>;
ReactDOM.render(
virtualDom,
document.getElementById('root')
);
12
Hello World
<!-- hello-world.html -->
<div id="root"></div>
// hello-world.jsx
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
13
https://facebook.github.io/react/docs/hello-world.html
Hello World
// This is translated by Babel to...
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
// ...to this
ReactDOM.render(React.createElement(
'h1',
null,
'Hello, world!'
), document.getElementById('root'));
14
https://babeljs.io/repl
• ReactJS only updates what changes
• Although everything is regenerated every time
• Open countdown example at codepen with chrome

http://codepen.io/drpicox/pen/yMKWGN
• Inspect page
• You can see that only the span is updated

(although this crude code changes everything)
Do not fear change
15
JSX
https://facebook.github.io/react/docs/introducing-jsx.html
JSX
// Just sugar syntax
const element = <h1>Hello, world!</h1>;
// It is just one object
const element = React.createElement(
"h1",
null,
"Hello, world!"
);
// one object that you can manipulate as object
17
JSX
// May I?
console.log(<h1>Hello!</h1>);
console.log(<h1>Hello!</h1>.toString());
console.log([<h1>Hello!</h1>]);
console.log({hello: <h1>Hello!</h1>});
console.log((() => <h1>Hello!</h1>)());
const salute = (what) => <h1>{what}!</h1>;
console.log(salute('Hello'));
18
JSX
// Have multiple elements (but one wrapper)
const element = <h1><span>Hello</span>, world!</h1>;
// Generates
const element = React.createElement(
"h1",
null,
React.createElement(
"span",
null,
"Hello"
),
", world!"
);
19
JSX
// It can be multiline (be careful using return)
const element =
<h1>
Hello, world!
</h1>;
20
JSX
// It can be multiline (better)
const element = <h1>
Hello, world!
</h1>;
21
JSX
// It can be multiline (recommended)
const element = (
<h1>
Hello, world!
</h1>
);
22
JSX - Interpolation
// Interpolate any JS expression
const name = 'bob hoskings';
const element = (
<h1>
Hello, {name}!
</h1>
);
// It is just one argument more
const element = React.createElement(
'h1',
null,
'Hello, ',
name,
'!'
);
23
JSX - Interpolation
// Interpolate any JS expression
const user = {name:'bob', lastName:'hoskings'};
const element = (
<h1>
Hello, {user.name + ' ' + user.lastName}!
</h1>
);
// It is still just one argument more
const element = React.createElement(
'h1',
null,
'Hello, ',
user.name + ' ' + user.lastName,
'!'
);
24
JSX - Interpolation
// any expression, including JSX
const element = <h1>Hello, {<span>world</span>}!</h1>
// It is still just one argument more
const element = React.createElement(
"h1",
null,
"Hello, ",
React.createElement(
"span",
null,
"world"
),
"!"
);
25
JSX - Properties
// Add attributes
const element = <div tabIndex="0">...</div>;
// Is transformed into a property object (alias props)
const element = React.createElement(
"div",
{ tabIndex: "0" },
"..."
);
26
JSX - Properties
// Add computed attributes
const element = <img src={user.imageUrl} />;
// Is transformed into a property object (alias props)
const element = React.createElement(
"img",
{ src: user.imageUrl },
);
27
JSX - Properties
// Set variable attributes
const options = {
autoplay: true,
muted: true,
};
const element = <video src="wow.mp4" {...options} />;
// Are merged into attribute
const element = React.createElement(
"video",
{
src: "wow.mp4",
...options
},
);
28
JSX - Properties
// Set variable attributes
const options = {
autoplay: true,
muted: true,
};
const element = <video src="wow.mp4" {...options} />;
// Are merged into attribute
const element = React.createElement(
"video",
{
src: "wow.mp4",
autoplay: true, muted: true
},
);
29
Properties vs Attributes
<!-- html uses attributes -->
<img id="hello" src="hello.jpg">
<!-- javascript uses properties -->
const helloImg = document.getElementById('hello');
console.log(helloImg.src);
30
Properties vs Attributes
<!-- html uses attributes -->
<h1 id="hello" class="big">Hello</h1>
<!-- javascript uses properties -->
const helloH1 = document.getElementById('hello');
console.log(helloH1.className);
31
JSX - Properties
// Because bad IE8 habits: className instead of class
const element = <h1 className="big">Hello</h1>;
// Is rendered as real html attribute:
<h1 class="big">Hello</h1>
32
JSX - Cross-site-scripting
// It is just a string
const title = response.veryMaliciousInputString;
// This is save
const element = <h1>{title}</h1>;
33
JSX - XML
// Is XML-like
const element = (
<div>
Hello <br/> World
</div>
);
// Elements must be terminated
const element = (
<div>
Hello <br> World
</div>
);
34
Rendering Elements
https://facebook.github.io/react/docs/rendering-elements.html
Rendering Elements
// JSX elements are just memory objects
const element = <h1>Hello, world</h1>;
36
Rendering Elements
// Given an html DOM element
<div id="root"></div>
// they can be rendered inside DOM
const domElement = document.getElementById('root');
const reactElement = <h1>Hello, world</h1>;
ReactDOM.render(
reactElement,
/* into */ domElement
);
37
Rendering Elements
// As many times as you want
// react only updates changes
const domElement = document.getElementById('root');
let n = 0;
setInterval(() => {
ReactDOM.render(<h1>{n += 1}</h1>, domElement);
}, 1000);
38
Components and Props
https://facebook.github.io/react/docs/components-and-
props.html
Components
// Can be defined as functions
const HelloWorld = () => {
return <h1>Hello, world</h1>;
};
export default HelloWorld;
40
Components
// Can be defined as functions
const HelloWorld = () => {
return <h1>Hello, world</h1>;
};
export default HelloWorld;
// Can be defined as classes
export default class HelloWorld extends React.Component
{
render() {
return <h1>Hello, world</h1>;
}
}
41
Component and properties
const element = <Welcome name="Dave" />;
42
Component and properties
const element = <Welcome name="Dave" />;
// Remember: it is like write
const element = React.createElement(
Welcome,
{ name: "Dave" }, // are called props
);
43
Component and properties
const element = <Welcome name="Dave" />;
// This is how you define the Component to use props
function Welcome(props) {
return (
<h1>Hello {props.name}!</h1>
);
}
44
Component and properties
const element = <Welcome name="Dave" />;
// This is how you define the Component to use props
class Welcome extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<h1>Hello {this.rops.name}!</h1>
);
}
}
45
Composing Components
function App() {
return (
<div>
<Welcome name="Alice" />
</div>
);
}
46
Composing Components
function App() {
return (
<div>
<Welcome name="Alice" />
<Welcome name="Bob" />
<Welcome name="Dave" />
</div>
);
}
47
Refactoring Components
function Component(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name}
/>
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
48
Refactoring Components
function Avatar(props) {
return (
<img className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name}
/>
);
}
49
<img className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name}
/>
Refactoring Components
function Component(props) {
return (
<div className="Comment">
<div className="UserInfo">
<Avatar user={props.author} />
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
50
Refactoring Components
function Component(props) {
return (
<div className="Comment">
<div className="UserInfo">
<Avatar user={props.author} />
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
51
Refactoring Components
function UserInfo(props) {
return (
<div className="UserInfo">
<Avatar user={props.user} />
<div className="UserInfo-name">
{props.user.name}
</div>
</div>
);
}
52
Refactoring Components
function Component(props) {
return (
<div className="Comment">
<UserInfo user={props.author} />
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
53
Props are Read-Only
// Render must be read-only
function MissbehavingComponent(props) {
return <h1>{props.n += 1}</h1>;
}
54
State and Lifecycle
https://facebook.github.io/react/docs/state-and-lifecycle.html
Function to Class Component
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.time}.</h2>
</div>
);
}
56
Function to Class Component
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.time}.</h2>
</div>
);
}
}
57
Function to Class Component
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.time}.</h2>
</div>
);
}
}
58
Setup State
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {time: Date.now()};
}
render() { ... }
}
59
Setup State
class Clock extends React.Component {
constructor(props) { ... }
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.time}.</h2>
</div>
);
}
}
60
Lifecycle Methods
class Clock extends React.Component {
constructor(props) { ... }
componentDidMount() { /* TODO */ }
componentWillUnmount() { /* TODO */ }
render() { ... }
}
61
Lifecycle Methods
class Clock extends React.Component {
constructor(props) { ... }
componentDidMount() {
this.timerId = setInterval(
() => this.setState({time: Date.now()}),
1000
);
}
componentWillUnmount() { /* TODO */ }
render() { ... }
}
62
Lifecycle Methods
class Clock extends React.Component {
constructor(props) { ... }
componentDidMount() { ... }
componentWillUnmount() {
clearInterval(this.timerId);
}
render() { ... }
}
63
setState Asynchronous
// Wrong!
setState({counter: this.state.counter + 1});
// Correct
setState((prevState, props) => ({
counter: prevState.counter + 1
});
64
States are Merged
constructor() {
this.state = {posts: [], users: []};
}
componentDidMount() {
getPosts((posts) => this.setState({posts}));
getUsers((users) => this.setState({users}));
}
65
State Isolated
function App() {
return (
<div>
<Clock />
<Clock />
<Clock />
</div>
);
}
66
Handling Events
https://facebook.github.io/react/docs/handling-events.html
onEvent={fn}
function ButtonLogHello() {
function handleClick() {
console.log('The button is clicked');
}
return (
<button onClick={handleClick}>
click me
</button>
);
}
68
onEvent={fn}
// It received the event as parameter
function ALogHello() {
function handleClick(ev) {
ev.preventDefault();
console.log('The link is clicked');
}
return (
<a href="#" onClick={handleClick}>
click me
</a>
);
}
69
onEvent={fn}
// It can inline functions (are expressions)
function DivLogHello() {
return (
<button onClick={() => console.log('oh')}>
click me
</button>
);
}
70
Toggle Example
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isToggleOn: true };
}
...
71
Toggle Example
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isToggleOn: true };
}
handleClick() { ... }
...
72
Toggle Example
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isToggleOn: true };
// This binding is necessary by `this`
this.handleClick = this.handleClick.bind(this);
}
handleClick() { ... }
...
73
Toggle Example
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isToggleOn: true };
// Fat arrow function preserves `this`
this.handleClick = () => { ... };
}
...
74
Toggle Example
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isToggleOn: true };
}
// Stage 2 alternative (recommended official)
handleClick = () => { ... }
...
75
Toggle Example
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isToggleOn: true };
}
handleClick = () => { … }
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'on' : 'off'}
</button>
);
}
}
76
Toggle Example
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isToggleOn: true };
}
handleClick = () => {
// Warning, wrong implementation
this.setState({ isToggleOn: !this.state.isToggleOn });
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'on' : 'off'}
</button>
);
}
}
77
Toggle Example
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isToggleOn: true };
}
handleClick = () => {
this.setState((prevState) => ({
isToggleOn: !prevState.isToggleOn,
});
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'on' : 'off'}
</button>
);
}
}
78
Conditional Rendering
https://facebook.github.io/react/docs/conditional-
rendering.html
Conditional Rendering
function UserGreeting(props) {
return <h1>Welcome back!</h1>;
}
function GuestGreeting(props) {
return <h1>Please sign up.</h1>;
}
80
By return
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
// Try changing to isLoggedIn={true}:
<Greeting isLoggedIn={false} />,
document.getElementById('root')
);
81
By variable
render() {
const isLoggedIn = this.state.isLoggedIn;
let button = null;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} /
>;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}
82
By && expression
function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread
messages.
</h2>
}
</div>
);
}
83
By ?: expression
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
{isLoggedIn ? (
<LogoutButton
onClick={this.handleLogoutClick} />
) : (
<LoginButton onClick={this.handleLoginClick} />
)}
</div>
);
}
84
Prevent Render
function WarningBanner(props) {
if (!props.warn) {
return null;
}
return (
<div className="warning">
Warning!
</div>
);
}
85
Lists and Keys
https://facebook.github.io/react/docs/lists-and-keys.html
Remember...
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((n) => n * 2);
console.log(doubled);
// [2, 4, 6, 8, 10]
87
Render Multiple
// Render a reactElements array
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li>{number}</li>
);
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);
88
Render Multiple
// Refactor into component
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li>{number}</li>
);
return (
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
89
Key
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
}
90
Key - index
const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs
<li key={index}>
{todo.text}
</li>
);
91
Key - Refactor Component
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
}
92
Key - Refactor Component
function ListItem(props) {
return (
// Wrong! should not be here
<li key="props.number.toString()">
{props.number}
</li>
);
}
93
Key - Refactor Component
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// Correct: key must remain with map
<ListItem key={number.toString()}
number={number} />
{number}
);
return (
<ul>{listItems}</ul>
);
}
94
Key - Uniqueness
// Cannot repeat keys in the same list, but...
function DoubleList(props) {
return (
<div>
<NumberList numbers={props.numbers} />
<NumberList numbers={props.numbers} />
<NumberList numbers={props.numbers} />
</div>
);
}
95
.map inside JSX
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{numbers.map((number) =>
<ListItem key={number.toString()}
value={number} />
)}
</ul>
);
}
96
Forms
https://facebook.github.io/react/docs/forms.html
Controlled Components
class NameForm extends React.Component {
constructor() { ... }
handleChange = (event) => {
this.setState({value: event.target.value});
}
handleSubmit = (event) => { ... }
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="text"
value={this.state.value}
onChange={this.handleChange} />
</form>
);
}
}
98
Controlled Components
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
}
handleChange = (event) => { ... }
handleSubmit = (event) => { ... }
render() { ... }
}
99
Controlled Components
class NameForm extends React.Component {
constructor() { ... }
handleChange = (event) => {
this.setState({
value: event.target.value.toLowerCase()
});
}
handleSubmit = (event) => { ... }
render() { ... }
}
100
Textarea
<textarea
value={this.state.value}
onChange={this.handleChange}
/>
101
Select
<select
value={this.state.value}
onChange={this.handleChange}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
102
Multiple Inputs
<input
name="isGoing" type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange} />
<input
name="numberOfGuests" type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange} />
103
Multiple Inputs
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ?
target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
104
Synchronized States
https://facebook.github.io/react/docs/lifting-state-up.html
Synchronizing - Consumer
// We want an <input> to generate new values for
function BoilingVerdict(props) {
if (props.celsius >= 100) {
return <p>The water would boil.</p>;
}
return <p>The water would not boil.</p>;
}
106
Synchronizing - Coordinator
class Calculator extends React.Component {
constructor(props) { ... }
handleChange = (e) =>
this.setState({temperature: e.target.value});
render() {
const temperature = this.state.temperature;
return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input value={temperature}
onChange={this.handleChange} />
<BoilingVerdict
celsius={parseFloat(temperature)} />
</fieldset>
);
}
}
107
Synchronizing - Producer
class Calculator extends React.Component {
constructor(props) { ... }
handleChange = (e) =>
this.setState({temperature: e.target.value});
render() {
const temperature = this.state.temperature;
return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input value={temperature}
onChange={this.handleChange} />
<BoilingVerdict
celsius={parseFloat(temperature)} />
</fieldset>
);
}
}
108
Synchronizing - Producer
class TemperatureInputCelsius extends React.Component {
constructor(props) { ... }
render() {
const temperature = this.state.temperature;
return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input value={temperature}
onChange={this.handleChange} />
</fieldset>
);
}
}
109
Synchronizing - Producer
class TemperatureInputCelsius extends React.Component {
constructor(props) { ... }
handleChange
render() {
const temperature = this.state.temperature;
return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input value={temperature}
onChange={this.handleChange} />
</fieldset>
);
}
}
110
Synchronizing - Producer
class TemperatureInputCelsius extends React.Component {
constructor(props) { ... }
handleChange = (e) =>
this.setState({temperature: e.target.value});
render() {
const temperature = this.state.temperature;
return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input value={temperature}
onChange={this.handleChange} />
</fieldset>
);
}
}
111
Synchronizing - Producer
class TemperatureInputCelsius extends React.Component {
constructor(props) { ... }
handleChange = (e) =>
this.setState({temperature: e.target.value});
render() {
const temperature = this.state.temperature;
return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input value={temperature}
onChange={this.handleChange} />
</fieldset>
);
}
}
112
Synchronizing - Coordinator
class Calculator extends React.Component {
constructor(props) { ... }
handleChange = (...?) =>
this.setState({temperature: ...?});
render() {
const temperature = this.state.temperature;
return (
<TemperatureInputCelsius ...? ...? />
<BoilingVerdict
celsius={parseFloat(temperature)} />
</fieldset>
);
}
}
113
Synchronizing - Coordinator
class Calculator extends React.Component {
constructor(props) { ... }
handleChange = (temperature) =>
this.setState({temperature: temperature});
render() {
const temperature = this.state.temperature;
return (
<TemperatureInputCelsius
temperature={temperature}
onTemperatureChange={this.handleChange} />
<BoilingVerdict
celsius={parseFloat(temperature)} />
</fieldset>
);
}
}
114
Synchronizing - Producer
class TemperatureInputCelsius extends React.Component {
constructor(props) { ... }
handleChange = (e) =>
this.setState({temperature: e.target.value});
render() {
const temperature = this.state.temperature;
return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input value={temperature}
onChange={this.handleChange} />
</fieldset>
);
}
}
115
Synchronizing - Producer
class TemperatureInputCelsius extends React.Component {
constructor(props) { ... }
handleChange = (e) =>
this.props.onTemperatureChange(e.target.value);
render() {
const temperature = this.props.temperature;
return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input value={temperature}
onChange={this.handleChange} />
</fieldset>
);
}
}
116
Synchronizing - Coordinator
117
Calculator
this: { handleChange }
state: { temperature }
props: { temperature }
BoilingVeredict
props: { temperature,
onTemperatureChange }
TemperatureInputCelsius
Synchronizing - Multiple Producer
Calculator
TemperatureInput => Celsius and Fahrenheit
118
Synchronizing - Producer
class TemperatureInput extends React.Component {
constructor(props) { ... }
handleChange = (e) =>
this.setState({temperature: e.target.value});
render() {
const temperature = this.state.temperature;
const scaleName = scaleNames[this.props.scale];
return (
<fieldset>
<legend>Enter temperature in {scaleName}:</
legend>
<input value={temperature}
onChange={this.handleChange} />
</fieldset>
);
}
}
119
Synchronizing - Producer
class Calculator extends React.Component {
constructor(props) { ... }
handleChange = (e) =>
this.setState({temperature: ...?});
render() {
const temperature = this.state.temperature;
return (
<div>
<TemperatureInput scale="c" ...? ...? />
<TemperatureInput scale="f" ...? ...? />
<BoilingVerdict
celsius={parseFloat(temperature)} />
</div>
);
}
}
120
Synchronizing - Producer
class TemperatureInput extends React.Component {
constructor(props) { ... }
handleChange = (e) =>
this.props.onTemperatureChange(e.target.value);
render() {
const temperature = this.props.temperature;
const scaleName = scaleNames[this.props.scale];
return (
<fieldset>
<legend>Enter temperature in {scaleName}:</
legend>
<input value={temperature}
onChange={this.handleChange} />
</fieldset>
);
}
}
121
Synchronizing - Coordinator
class Calculator extends React.Component {
constructor(props) { ... }
handleChange = (e) =>
this.setState({temperature: ...?});
render() {
const temperature = this.state.temperature;
return (
<div>
<TemperatureInput scale="c" ...? ...? />
<TemperatureInput scale="f" ...? ...? />
<BoilingVerdict
celsius={parseFloat(temperature)} />
</div>
);
}
}
122
Coordinator - Inputs
class Calculator extends React.Component {
...
render() {
const scale = this.state.scale;
const temperature = this.state.temperature;
const celsius = convertIf(scale === 'f', temperature,
toCelsius);
const fahrenheit = convertIf(scale === 'c', temperature,
toFahrenheit);
return (
<div>
<TemperatureInput scale="c" temperature={celsius} ...? />
<TemperatureInput scale="f" temperature={fahrenheit} ...? />
<BoilingVerdict
celsius={parseFloat(celsius)} />
</div>
);
}
}
123
Coordinator Outputs
class Calculator extends React.Component {
...
handleCelsiusChange = (temperature) =>
this.setState({scale: 'c', temperature});
handleFahrenheitChange = (temperature) =>
this.setState({scale: 'f', temperature});
render() {
const scale = this.state.scale;
const temperature = this.state.temperature;
const celsius = convertIf(scale === 'f', temperature,
toCelsius);
...
<TemperatureInput scale="c" temperature={celsius}
onTemperatureChange={this.handleCelsiusChange} />
<TemperatureInput scale="f" temperature={fahrenheit}
onTemperatureChange={this.handleFahrenheitChange} />
...
}
}
124
Coordinator Outputs
function convertIf(test, temperature, convert) {
if (test) {
return tryConvert(temperature, convert);
}
return temperature;
}
125
Exercise
126
https://codepen.io/drpicox/pen/ryrypJ
Exercise React Temperature
Component Composition
https://facebook.github.io/react/docs/composition-vs-
inheritance.html
Java 1.0
128
http://web.mit.edu/java_v1.0.2/www/apibook/javag2.htm
An application should override the action method (II-
§1.10.1) of the button or of one of its containing windows
in order to cause some action to occur.
Button
+ action(...)
MyButton
+ action(...)
Java 1.1
129
In 1.1, we aimed at solving some major AWT (Abstract
Window Toolkit) deficiencies, with a strong focus on quality
and performance. The AWT enhancements include [...], a
delegation-based event model, [...].
Button
+ actionActionListener(...)
https://www.cs.princeton.edu/courses/archive/fall97/cs461/
jdkdocs/guide/awt/index.html
<i> ActionListener
+ actionPerformed(...) = 0
MyActionListener
+ actionPerformed(...)
*
Java 1.2
130
When an Action object is added to such a container, the container:
Creates a component that is appropriate for that container (a toolbar
creates a button component, for example), Gets the appropriate
property(s) from the Action object to customize the component (for
example, the icon image and flyover text)....
<i> Action
+ actionPerformed(...) = 0
+ isEnabled(): bool
+ setEnabled(b)
+ getValue(key): Object
+ putValue(key, value)
+ addPropertyChangeListener(...)
+ removePropertyChangeListener(...)
http://www.kbs.twi.tudelft.nl/Documentation/Programming/
Java/jdk1.2/api/javax/swing/Action.html
Children Composition
131
Card
Contents
Children Composition
<Card>
<h1>Welcome</h1>
<p>
Find here a complete list
of all the things that you
love.
</p>
</Card>
132
Children Composition
function Card(props) {
return (
<div className="card">
{props.children}
</div>
);
}
133
Many Children Composition
134
SplitPane
Left Right
Many Children Composition
<div class="SplitPane">
<div class="SplitPane-left">
<Contacts />
</div>
<div class="SplitPane-right">
<Chat />
</div>
</div>
135
Many Children Composition
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}
136
Many Children Composition
function App() {
return (
<SplitPane
left={ <Contacts /> }
right={ <Chat /> }
/>
);
}
137
Specialization
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
</FancyBorder>
);
}
138
Specialization
function WelcomeDialog(props) {
return (
<Dialog
title="Welcome"
message="Thanks for visiting!" />
);
}
139
Specialization
function WelcomeDialog(props) {
return (
<Dialog
title="Welcome"
message={
<div>
<h1>Thanks!</h1>
for visiting!
</div>
} />
);
}
140
High Order Components
https://facebook.github.io/react/docs/higher-order-
components.html
Like high order functions
const safeConvert = (convert) => {
return (temperature) => {
const input = parseFloat(temperature);
if (Number.isNaN(input)) {
return '';
}
const output = convert(input);
const rounded = Math.round(output * 100) / 100;
return rounded.toString();
}
}
142
Like high order functions
const safeConvert = (convert) => {
return (temperature) => {
...
}
}
const safeKelvinToCelsius =
safeConvert(kelvinToCelsius);
const celsius = safeKelvinToCelsius(kelvin);
143
Specific Component
class TemperatureInputCelsius extends React.Component {
handleChange = (e) => this.props.onTemperatureChange(
safeCelsiusToKelvin(e.target.value);
);
render() {
const temperature = this.props.temperature;
const celsius = safeKelvinToCelsius(temperature);
return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input value={temperature}
onChange={this.handleChange} />
</fieldset>
);
}
}
144
Specific Component
class TemperatureInputFahrenheit extends React.Component {
handleChange = (e) => this.props.onTemperatureChange(
safeFahrenheitToKelvin(e.target.value);
);
render() {
const temperature = this.props.temperature;
const celsius = safeKelvinToFahrenheit(temperature);
return (
<fieldset>
<legend>Enter temperature in Fahrenheit:</legend>
<input value={temperature}
onChange={this.handleChange} />
</fieldset>
);
}
}
145
Generic Component
class TemperatureInput? extends React.Component {
handleChange = (e) => this.props.onTemperatureChange(
toKelvin(e.target.value);
);
render() {
const temperature = this.props.temperature;
const local = toLocal(temperature);
return (
<fieldset>
<legend>Enter temperature in {scaleName}:</
legend>
<input value={local}
onChange={this.handleChange} />
</fieldset>
);
}
}
146
Generic Component
function makeTemperatureInput(toKelvin, toLocal, scaleName) {
return class extends React.Component {
handleChange = (e) => this.props.onTemperatureChange(
toKelvin(e.target.value);
);
render() {
const temperature = this.props.temperature;
const local = toLocal(temperature);
return (
<fieldset>
<legend>Enter temperature in {scaleName}:</legend>
<input value={local}
onChange={this.handleChange} />
</fieldset>
);
}
}
}
147
Using Generic Component
const TemperatureInputCelsius = makeTemperatureInput(
safeCelsiusToKelvin,
safeKelvinToCelsius,
'Celsius'
);
const TemperatureInputFahrenheit = makeTemperatureInput(
safeFahrenheitToKelvin,
safeKelvinToFahrenheit,
'Fahrenheit'
);
const TemperatureInputKelvin = makeTemperatureInput(
identity,
identity,
'Kelvin'
);
148
Using Generic Component
const TemperatureInputCelsius = makeTemperatureInput(
safeConvert(celsiusToKelvin),
safeConvert(kelvinToCelsius),
'Celsius'
);
const TemperatureInputFahrenheit = makeTemperatureInput(
safeConvert(fahrenheitToKelvin),
safeConvert(kelvinToFahrenheit),
'Fahrenheit'
);
const TemperatureInputKelvin = makeTemperatureInput(
(x) => x,
(x) => x,
'Kelvin'
);
149
High Order Component
class Thermostat extends React.Component {
constructor(props) { ... }
handleChangeMax = (e) => ...
handleChangeMin = (e) => ...
render() {
return (
<div>
Max <TemperatureInput
temperature={this.state.max}
onTemperatureChange={this.handleChangeMax} />
Min <TemperatureInput
temperature={this.state.min}
onTemperatureChange={this.handleChangeMin} />
</div>
);
}
}
150
High Order Component
function makeThermostat(TemperatureInput) {
return class extends React.Component {
constructor(props) { ... }
handleChangeMax = (e) => ...
handleChangeMin = (e) => ...
render() {
return (
<div>
Max <TemperatureInput temperature={this.state.max}
onTemperatureChange={this.handleChangeMax} />
Min <TemperatureInput temperature={this.state.max}
onTemperatureChange={this.handleChangeMax} />
</div>
);
}
}
}
151
High Order Component
function makeThermostat(TemperatureInput) {
return class extends React.Component {
...
}
}
const ThermostatCelsius =
makeThermostat(TemperatureInputCelsius);
const ThermostatFahrenheit =
makeThermostat(TemperatureInputFahrenheit);
const ThermostatKelvin =
makeThermostat(TemperatureInputKelvin);
152
Debug: displayName
function makeTemperatureInput(
toKelvin, toFahrenheit, scaleName
) {
class TemperatureInput extends React.Component {
...
}
TemperatureInput.displayName =
`TemperatureInput(${scaleName})`;
return TemperatureInput;
}
153
Debug: displayName
function makeThermostat(TemperatureInput) {
class Thermostat extends React.Component {
...
}
Thermostat.displayName =
`Thermostat(${getDisplayName(TemperatureInput)})`;
return Thermostat;
}
154
Warning!
// DON'T use HOCs in render functions!
const App = () => {
const TemperatureInputAbc =
makeTemperatureInput(a, b, c);
return <TemperatureInputAbc />;
}
class App extends React.Component {
render() {
const TemperatureInputAbc =
makeTemperatureInput(a, b, c);
return <TemperatureInputAbc />;
}
}
155
More in docs
• Use HOCs For Cross-Cutting Concerns
• Don't Mutate the Original Component. 

Use Composition.
• Convention: Pass Unrelated Props Through to the Wrapped
Component
• Convention: Maximizing Composability
• Convention: Wrap the Display Name for Easy Debugging
• Caveats
156
Containers
https://medium.com/@dan_abramov/smart-and-dumb-
components-7ca2f9a7c7d0
Convention
• Types of components
• Routers
• Containers
• Presentational
158
Routes
• Routers
• Decides which component to render
• Create components dynamically
• Usually provided by library
159
Containers
• Knows how to load or mutate data
• Observe Stores
• Dispatch Actions
• Other system interactions
• Always stateful (class notation)
• Renders nothing
• Delegates render to a Presentational Component
• Configures its props
160
Presentational
• Knows how to render things
• Data and callbacks only via props
• does not interact with the application
• Usually functional (not need state)
• Also called Components
161
class Clock extends React.Component {
constructor(props) { ... }
componentDidMount() {
this.timerId = setInterval(
() => this.setState({time: Date.now()}),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerId);
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.time}.</h2>
</div>
);
}
}
162
Presentational
Container
class Clock extends React.Component {
constructor(props) { ... }
componentDidMount() {
this.timerId = setInterval(
() => this.setState({time: Date.now()}),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerId);
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.time}.</h2>
</div>
);
}
}
163
Presentational
Container
Presentational Refactor
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.time}.</h2>
</div>
);
}
164
Container Refactor
class IntervalClock extends React.Component {
constructor(props) { ... }
componentDidMount() {
this.timerId = setInterval(
() => this.setState({time: Date.now()}),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerId);
}
render() {
return <Clock time={this.state.time} />;
}
}
165
Container Refactor
function makeIntervalClock(Clock) {
return class extends React.Component {
constructor(props) { ... }
componentDidMount() {
this.timerId = setInterval(
() => this.setState({time: Date.now()}),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerId);
}
render() {
return <Clock time={this.state.time} />;
}
};
}
166
PropTypes
https://facebook.github.io/react/docs/typechecking-with-
proptypes.html
PropTypes
import PropTypes from 'prop-types';
export default function Welcome(props) {
return (
<h1>Hello, {props.name}</h1>
);
}
Welcome.propTypes = {
name: PropTypes.string
};
168
https://facebook.github.io/react/docs/typechecking-with-proptypes.html
PropTypes
import PropTypes from 'prop-types';
export default class Welcome extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Welcome.propTypes = {
name: PropTypes.string.isRequired
};
169
https://facebook.github.io/react/docs/typechecking-with-proptypes.html

More Related Content

PDF
Introduction to web programming for java and c# programmers by @drpicox
David Rodenas
 
PDF
TDD CrashCourse Part4: Improving Testing
David Rodenas
 
PDF
JS and patterns
David Rodenas
 
PDF
Testing, Learning and Professionalism — 20171214
David Rodenas
 
PDF
TDD CrashCourse Part5: Testing Techniques
David Rodenas
 
PDF
ES3-2020-07 Testing techniques
David Rodenas
 
PDF
ES3-2020-06 Test Driven Development (TDD)
David Rodenas
 
PDF
Redux for ReactJS Programmers
David Rodenas
 
Introduction to web programming for java and c# programmers by @drpicox
David Rodenas
 
TDD CrashCourse Part4: Improving Testing
David Rodenas
 
JS and patterns
David Rodenas
 
Testing, Learning and Professionalism — 20171214
David Rodenas
 
TDD CrashCourse Part5: Testing Techniques
David Rodenas
 
ES3-2020-07 Testing techniques
David Rodenas
 
ES3-2020-06 Test Driven Development (TDD)
David Rodenas
 
Redux for ReactJS Programmers
David Rodenas
 

What's hot (20)

KEY
Inside PyMongo - MongoNYC
Mike Dirolf
 
PDF
Pyconie 2012
Yaqi Zhao
 
PPT
Spock Framework
Леонид Ставила
 
PPTX
Building unit tests correctly
Dror Helper
 
PPTX
Unit testing patterns for concurrent code
Dror Helper
 
PDF
關於測試,我說的其實是......
hugo lu
 
PDF
Spock Testing Framework - The Next Generation
BTI360
 
PDF
Java Bytecode for Discriminating Developers - JavaZone 2011
Anton Arhipov
 
PDF
Celery
Òscar Vilaplana
 
PDF
33rd Degree 2013, Bad Tests, Good Tests
Tomek Kaczanowski
 
PDF
GeeCON 2017 - TestContainers. Integration testing without the hassle
Anton Arhipov
 
PPTX
TDD Training
Manuela Grindei
 
PDF
Agile Android
Godfrey Nolan
 
PDF
Tomasz Polanski - Automated mobile testing 2016 - Testing: why, when, how
Tomasz Polanski
 
PDF
Workshop quality assurance for php projects - ZendCon 2013
Michelangelo van Dam
 
PDF
UA testing with Selenium and PHPUnit - PFCongres 2013
Michelangelo van Dam
 
PDF
Agile Swift
Godfrey Nolan
 
PDF
Maintainable JavaScript 2011
Nicholas Zakas
 
PPTX
Unit testing without Robolectric, Droidcon Berlin 2016
Danny Preussler
 
PPTX
15 tips to improve your unit tests (Droidcon Berlin 2016 Barcamp)
Danny Preussler
 
Inside PyMongo - MongoNYC
Mike Dirolf
 
Pyconie 2012
Yaqi Zhao
 
Building unit tests correctly
Dror Helper
 
Unit testing patterns for concurrent code
Dror Helper
 
關於測試,我說的其實是......
hugo lu
 
Spock Testing Framework - The Next Generation
BTI360
 
Java Bytecode for Discriminating Developers - JavaZone 2011
Anton Arhipov
 
33rd Degree 2013, Bad Tests, Good Tests
Tomek Kaczanowski
 
GeeCON 2017 - TestContainers. Integration testing without the hassle
Anton Arhipov
 
TDD Training
Manuela Grindei
 
Agile Android
Godfrey Nolan
 
Tomasz Polanski - Automated mobile testing 2016 - Testing: why, when, how
Tomasz Polanski
 
Workshop quality assurance for php projects - ZendCon 2013
Michelangelo van Dam
 
UA testing with Selenium and PHPUnit - PFCongres 2013
Michelangelo van Dam
 
Agile Swift
Godfrey Nolan
 
Maintainable JavaScript 2011
Nicholas Zakas
 
Unit testing without Robolectric, Droidcon Berlin 2016
Danny Preussler
 
15 tips to improve your unit tests (Droidcon Berlin 2016 Barcamp)
Danny Preussler
 
Ad

Similar to ReactJS for Programmers (20)

PDF
Basic Tutorial of React for Programmers
David Rodenas
 
PPT
ReactJS.ppt
MOMEKEMKUEFOUETDUREL
 
PPTX
React, Flux and a little bit of Redux
Ny Fanilo Andrianjafy, B.Eng.
 
PPTX
React workshop
Imran Sayed
 
PDF
ReactJS presentation
Thanh Tuong
 
PPTX
React Workshop: Core concepts of react
Imran Sayed
 
PDF
Introduction to React JS
Bethmi Gunasekara
 
PPTX
React_Complete.pptx
kamalakantas
 
PPTX
Internet and Web Technology (CLASS-9) [React.js] | NIC/NIELIT Web Technology
Ayes Chinmay
 
PPTX
2.React tttttttttttttttttttttttttttttttt
MrVMNair
 
PDF
Learn react by Etietop Demas
Etietop Demas
 
PDF
react.pdf
yihunie2
 
PDF
unit 3_Adv WTAdvanced Web Tecg Design_HTML_CSS_JAVASCRIPT_AJAX_PPT.pdf
GauravDwivedi695361
 
PDF
Getting Started with React, When You’re an Angular Developer
Fabrit Global
 
PDF
0900 learning-react
RohitYadav696
 
PPTX
ReactJS
Ram Murat Sharma
 
PDF
Stay with React.js in 2020
Jerry Liao
 
PDF
React & Flux Workshop
Christian Lilley
 
PPTX
React.js - The Dawn of Virtual DOM
Jimit Shah
 
PDF
30 days-of-react-ebook-fullstackio
imdurgesh
 
Basic Tutorial of React for Programmers
David Rodenas
 
React, Flux and a little bit of Redux
Ny Fanilo Andrianjafy, B.Eng.
 
React workshop
Imran Sayed
 
ReactJS presentation
Thanh Tuong
 
React Workshop: Core concepts of react
Imran Sayed
 
Introduction to React JS
Bethmi Gunasekara
 
React_Complete.pptx
kamalakantas
 
Internet and Web Technology (CLASS-9) [React.js] | NIC/NIELIT Web Technology
Ayes Chinmay
 
2.React tttttttttttttttttttttttttttttttt
MrVMNair
 
Learn react by Etietop Demas
Etietop Demas
 
react.pdf
yihunie2
 
unit 3_Adv WTAdvanced Web Tecg Design_HTML_CSS_JAVASCRIPT_AJAX_PPT.pdf
GauravDwivedi695361
 
Getting Started with React, When You’re an Angular Developer
Fabrit Global
 
0900 learning-react
RohitYadav696
 
Stay with React.js in 2020
Jerry Liao
 
React & Flux Workshop
Christian Lilley
 
React.js - The Dawn of Virtual DOM
Jimit Shah
 
30 days-of-react-ebook-fullstackio
imdurgesh
 
Ad

More from David Rodenas (17)

PDF
TDD CrashCourse Part2: TDD
David Rodenas
 
PDF
TDD CrashCourse Part1: Testing
David Rodenas
 
PDF
TDD CrashCourse Part3: TDD Techniques
David Rodenas
 
PDF
Be professional: We Rule the World
David Rodenas
 
PDF
ES3-2020-P3 TDD Calculator
David Rodenas
 
PDF
ES3-2020-P2 Bowling Game Kata
David Rodenas
 
PDF
ES3-2020-05 Testing
David Rodenas
 
PDF
Vespres
David Rodenas
 
PDF
Faster web pages
David Rodenas
 
PPTX
From high school to university and work
David Rodenas
 
PDF
Modules in angular 2.0 beta.1
David Rodenas
 
PDF
Freelance i Enginyeria
David Rodenas
 
PDF
Angular 1.X Community and API Decissions
David Rodenas
 
PDF
MVS: An angular MVC
David Rodenas
 
PDF
Mvc - Model: the great forgotten
David Rodenas
 
PDF
(automatic) Testing: from business to university and back
David Rodenas
 
PDF
Testing: ¿what, how, why?
David Rodenas
 
TDD CrashCourse Part2: TDD
David Rodenas
 
TDD CrashCourse Part1: Testing
David Rodenas
 
TDD CrashCourse Part3: TDD Techniques
David Rodenas
 
Be professional: We Rule the World
David Rodenas
 
ES3-2020-P3 TDD Calculator
David Rodenas
 
ES3-2020-P2 Bowling Game Kata
David Rodenas
 
ES3-2020-05 Testing
David Rodenas
 
Vespres
David Rodenas
 
Faster web pages
David Rodenas
 
From high school to university and work
David Rodenas
 
Modules in angular 2.0 beta.1
David Rodenas
 
Freelance i Enginyeria
David Rodenas
 
Angular 1.X Community and API Decissions
David Rodenas
 
MVS: An angular MVC
David Rodenas
 
Mvc - Model: the great forgotten
David Rodenas
 
(automatic) Testing: from business to university and back
David Rodenas
 
Testing: ¿what, how, why?
David Rodenas
 

Recently uploaded (20)

PDF
Generating Union types w/ Static Analysis
K. Matthew Dupree
 
PDF
Applitools Platform Pulse: What's New and What's Coming - July 2025
Applitools
 
PDF
What to consider before purchasing Microsoft 365 Business Premium_PDF.pdf
Q-Advise
 
PPTX
Presentation about Database and Database Administrator
abhishekchauhan86963
 
PPTX
slidesgo-unlocking-the-code-the-dynamic-dance-of-variables-and-constants-2024...
kr2589474
 
PDF
Download iTop VPN Free 6.1.0.5882 Crack Full Activated Pre Latest 2025
imang66g
 
PDF
advancepresentationskillshdhdhhdhdhdhhfhf
jasmenrojas249
 
PDF
lesson-2-rules-of-netiquette.pdf.bshhsjdj
jasmenrojas249
 
PPTX
Role Of Python In Programing Language.pptx
jaykoshti048
 
PDF
WatchTraderHub - Watch Dealer software with inventory management and multi-ch...
WatchDealer Pavel
 
PDF
Teaching Reproducibility and Embracing Variability: From Floating-Point Exper...
University of Rennes, INSA Rennes, Inria/IRISA, CNRS
 
PDF
Exploring AI Agents in Process Industries
amoreira6
 
PDF
Adobe Illustrator Crack Full Download (Latest Version 2025) Pre-Activated
imang66g
 
PPTX
Explanation about Structures in C language.pptx
Veeral Rathod
 
PDF
Key Features to Look for in Arizona App Development Services
Net-Craft.com
 
PDF
vAdobe Premiere Pro 2025 (v25.2.3.004) Crack Pre-Activated Latest
imang66g
 
PPTX
AI-Ready Handoff: Auto-Summaries & Draft Emails from MQL to Slack in One Flow
bbedford2
 
PDF
New Download MiniTool Partition Wizard Crack Latest Version 2025
imang66g
 
PPTX
oapresentation.pptx
mehatdhavalrajubhai
 
PDF
49785682629390197565_LRN3014_Migrating_the_Beast.pdf
Abilash868456
 
Generating Union types w/ Static Analysis
K. Matthew Dupree
 
Applitools Platform Pulse: What's New and What's Coming - July 2025
Applitools
 
What to consider before purchasing Microsoft 365 Business Premium_PDF.pdf
Q-Advise
 
Presentation about Database and Database Administrator
abhishekchauhan86963
 
slidesgo-unlocking-the-code-the-dynamic-dance-of-variables-and-constants-2024...
kr2589474
 
Download iTop VPN Free 6.1.0.5882 Crack Full Activated Pre Latest 2025
imang66g
 
advancepresentationskillshdhdhhdhdhdhhfhf
jasmenrojas249
 
lesson-2-rules-of-netiquette.pdf.bshhsjdj
jasmenrojas249
 
Role Of Python In Programing Language.pptx
jaykoshti048
 
WatchTraderHub - Watch Dealer software with inventory management and multi-ch...
WatchDealer Pavel
 
Teaching Reproducibility and Embracing Variability: From Floating-Point Exper...
University of Rennes, INSA Rennes, Inria/IRISA, CNRS
 
Exploring AI Agents in Process Industries
amoreira6
 
Adobe Illustrator Crack Full Download (Latest Version 2025) Pre-Activated
imang66g
 
Explanation about Structures in C language.pptx
Veeral Rathod
 
Key Features to Look for in Arizona App Development Services
Net-Craft.com
 
vAdobe Premiere Pro 2025 (v25.2.3.004) Crack Pre-Activated Latest
imang66g
 
AI-Ready Handoff: Auto-Summaries & Draft Emails from MQL to Slack in One Flow
bbedford2
 
New Download MiniTool Partition Wizard Crack Latest Version 2025
imang66g
 
oapresentation.pptx
mehatdhavalrajubhai
 
49785682629390197565_LRN3014_Migrating_the_Beast.pdf
Abilash868456
 

ReactJS for Programmers

  • 4. FB about MVC 4 “MVC works pretty well for small applications… but it doesn’t make room for new features.” “Flux is a single direction data flow, that avoids all the arrows going on all directions what makes really hard to understand the system.”
  • 5. FB about Chat 5 “Let’s see a real good example: FB chat” “How we get to the point, so we were annoying our users so much the just they wanted us to fix chat?” “The problems here were: • The code has no structure • It was very imperative, that makes it fragile • It loose a lot of the original intend behind it, its hard to tell what it tries [to do] • Add more features only gets this code larger • We had our most annoying chat bug happen over and over • We were always fixing some pretty good edge case, the whole system was fragile • … • This code becomes more fragile with the time. • No member of the team wanted to touch it, they wanted to jump to any other bug.”
  • 6. FB about Rendering 6 “Imperative Rendering” “If renders all each time the screen flickers” “We wanted always render all, no matter what” “Here is where React comes in.”
  • 7. FB & Virtual DOM 7
  • 11. Hello World <!-- hello-world.html --> <div id="root"></div> // hello-world.js const virtualDom = React.createElement( 'h1', null, 'Hello, world!' ); ReactDOM.render( virtualDom, document.getElementById('root') ); 11
  • 12. Hello World <!-- hello-world.html --> <div id="root"></div> // hello-world.jsx const virtualDom = <h1>Hello, world!</h1>; ReactDOM.render( virtualDom, document.getElementById('root') ); 12
  • 13. Hello World <!-- hello-world.html --> <div id="root"></div> // hello-world.jsx ReactDOM.render( <h1>Hello, world!</h1>, document.getElementById('root') ); 13 https://facebook.github.io/react/docs/hello-world.html
  • 14. Hello World // This is translated by Babel to... ReactDOM.render( <h1>Hello, world!</h1>, document.getElementById('root') ); // ...to this ReactDOM.render(React.createElement( 'h1', null, 'Hello, world!' ), document.getElementById('root')); 14 https://babeljs.io/repl
  • 15. • ReactJS only updates what changes • Although everything is regenerated every time • Open countdown example at codepen with chrome
 http://codepen.io/drpicox/pen/yMKWGN • Inspect page • You can see that only the span is updated
 (although this crude code changes everything) Do not fear change 15
  • 17. JSX // Just sugar syntax const element = <h1>Hello, world!</h1>; // It is just one object const element = React.createElement( "h1", null, "Hello, world!" ); // one object that you can manipulate as object 17
  • 18. JSX // May I? console.log(<h1>Hello!</h1>); console.log(<h1>Hello!</h1>.toString()); console.log([<h1>Hello!</h1>]); console.log({hello: <h1>Hello!</h1>}); console.log((() => <h1>Hello!</h1>)()); const salute = (what) => <h1>{what}!</h1>; console.log(salute('Hello')); 18
  • 19. JSX // Have multiple elements (but one wrapper) const element = <h1><span>Hello</span>, world!</h1>; // Generates const element = React.createElement( "h1", null, React.createElement( "span", null, "Hello" ), ", world!" ); 19
  • 20. JSX // It can be multiline (be careful using return) const element = <h1> Hello, world! </h1>; 20
  • 21. JSX // It can be multiline (better) const element = <h1> Hello, world! </h1>; 21
  • 22. JSX // It can be multiline (recommended) const element = ( <h1> Hello, world! </h1> ); 22
  • 23. JSX - Interpolation // Interpolate any JS expression const name = 'bob hoskings'; const element = ( <h1> Hello, {name}! </h1> ); // It is just one argument more const element = React.createElement( 'h1', null, 'Hello, ', name, '!' ); 23
  • 24. JSX - Interpolation // Interpolate any JS expression const user = {name:'bob', lastName:'hoskings'}; const element = ( <h1> Hello, {user.name + ' ' + user.lastName}! </h1> ); // It is still just one argument more const element = React.createElement( 'h1', null, 'Hello, ', user.name + ' ' + user.lastName, '!' ); 24
  • 25. JSX - Interpolation // any expression, including JSX const element = <h1>Hello, {<span>world</span>}!</h1> // It is still just one argument more const element = React.createElement( "h1", null, "Hello, ", React.createElement( "span", null, "world" ), "!" ); 25
  • 26. JSX - Properties // Add attributes const element = <div tabIndex="0">...</div>; // Is transformed into a property object (alias props) const element = React.createElement( "div", { tabIndex: "0" }, "..." ); 26
  • 27. JSX - Properties // Add computed attributes const element = <img src={user.imageUrl} />; // Is transformed into a property object (alias props) const element = React.createElement( "img", { src: user.imageUrl }, ); 27
  • 28. JSX - Properties // Set variable attributes const options = { autoplay: true, muted: true, }; const element = <video src="wow.mp4" {...options} />; // Are merged into attribute const element = React.createElement( "video", { src: "wow.mp4", ...options }, ); 28
  • 29. JSX - Properties // Set variable attributes const options = { autoplay: true, muted: true, }; const element = <video src="wow.mp4" {...options} />; // Are merged into attribute const element = React.createElement( "video", { src: "wow.mp4", autoplay: true, muted: true }, ); 29
  • 30. Properties vs Attributes <!-- html uses attributes --> <img id="hello" src="hello.jpg"> <!-- javascript uses properties --> const helloImg = document.getElementById('hello'); console.log(helloImg.src); 30
  • 31. Properties vs Attributes <!-- html uses attributes --> <h1 id="hello" class="big">Hello</h1> <!-- javascript uses properties --> const helloH1 = document.getElementById('hello'); console.log(helloH1.className); 31
  • 32. JSX - Properties // Because bad IE8 habits: className instead of class const element = <h1 className="big">Hello</h1>; // Is rendered as real html attribute: <h1 class="big">Hello</h1> 32
  • 33. JSX - Cross-site-scripting // It is just a string const title = response.veryMaliciousInputString; // This is save const element = <h1>{title}</h1>; 33
  • 34. JSX - XML // Is XML-like const element = ( <div> Hello <br/> World </div> ); // Elements must be terminated const element = ( <div> Hello <br> World </div> ); 34
  • 36. Rendering Elements // JSX elements are just memory objects const element = <h1>Hello, world</h1>; 36
  • 37. Rendering Elements // Given an html DOM element <div id="root"></div> // they can be rendered inside DOM const domElement = document.getElementById('root'); const reactElement = <h1>Hello, world</h1>; ReactDOM.render( reactElement, /* into */ domElement ); 37
  • 38. Rendering Elements // As many times as you want // react only updates changes const domElement = document.getElementById('root'); let n = 0; setInterval(() => { ReactDOM.render(<h1>{n += 1}</h1>, domElement); }, 1000); 38
  • 40. Components // Can be defined as functions const HelloWorld = () => { return <h1>Hello, world</h1>; }; export default HelloWorld; 40
  • 41. Components // Can be defined as functions const HelloWorld = () => { return <h1>Hello, world</h1>; }; export default HelloWorld; // Can be defined as classes export default class HelloWorld extends React.Component { render() { return <h1>Hello, world</h1>; } } 41
  • 42. Component and properties const element = <Welcome name="Dave" />; 42
  • 43. Component and properties const element = <Welcome name="Dave" />; // Remember: it is like write const element = React.createElement( Welcome, { name: "Dave" }, // are called props ); 43
  • 44. Component and properties const element = <Welcome name="Dave" />; // This is how you define the Component to use props function Welcome(props) { return ( <h1>Hello {props.name}!</h1> ); } 44
  • 45. Component and properties const element = <Welcome name="Dave" />; // This is how you define the Component to use props class Welcome extends React.Component { constructor(props) { super(props); } render() { return ( <h1>Hello {this.rops.name}!</h1> ); } } 45
  • 46. Composing Components function App() { return ( <div> <Welcome name="Alice" /> </div> ); } 46
  • 47. Composing Components function App() { return ( <div> <Welcome name="Alice" /> <Welcome name="Bob" /> <Welcome name="Dave" /> </div> ); } 47
  • 48. Refactoring Components function Component(props) { return ( <div className="Comment"> <div className="UserInfo"> <img className="Avatar" src={props.author.avatarUrl} alt={props.author.name} /> <div className="UserInfo-name"> {props.author.name} </div> </div> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); } 48
  • 49. Refactoring Components function Avatar(props) { return ( <img className="Avatar" src={props.user.avatarUrl} alt={props.user.name} /> ); } 49 <img className="Avatar" src={props.author.avatarUrl} alt={props.author.name} />
  • 50. Refactoring Components function Component(props) { return ( <div className="Comment"> <div className="UserInfo"> <Avatar user={props.author} /> <div className="UserInfo-name"> {props.author.name} </div> </div> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); } 50
  • 51. Refactoring Components function Component(props) { return ( <div className="Comment"> <div className="UserInfo"> <Avatar user={props.author} /> <div className="UserInfo-name"> {props.author.name} </div> </div> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); } 51
  • 52. Refactoring Components function UserInfo(props) { return ( <div className="UserInfo"> <Avatar user={props.user} /> <div className="UserInfo-name"> {props.user.name} </div> </div> ); } 52
  • 53. Refactoring Components function Component(props) { return ( <div className="Comment"> <UserInfo user={props.author} /> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); } 53
  • 54. Props are Read-Only // Render must be read-only function MissbehavingComponent(props) { return <h1>{props.n += 1}</h1>; } 54
  • 56. Function to Class Component function Clock(props) { return ( <div> <h1>Hello, world!</h1> <h2>It is {props.time}.</h2> </div> ); } 56
  • 57. Function to Class Component class Clock extends React.Component { render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.props.time}.</h2> </div> ); } } 57
  • 58. Function to Class Component class Clock extends React.Component { render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.props.time}.</h2> </div> ); } } 58
  • 59. Setup State class Clock extends React.Component { constructor(props) { super(props); this.state = {time: Date.now()}; } render() { ... } } 59
  • 60. Setup State class Clock extends React.Component { constructor(props) { ... } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.time}.</h2> </div> ); } } 60
  • 61. Lifecycle Methods class Clock extends React.Component { constructor(props) { ... } componentDidMount() { /* TODO */ } componentWillUnmount() { /* TODO */ } render() { ... } } 61
  • 62. Lifecycle Methods class Clock extends React.Component { constructor(props) { ... } componentDidMount() { this.timerId = setInterval( () => this.setState({time: Date.now()}), 1000 ); } componentWillUnmount() { /* TODO */ } render() { ... } } 62
  • 63. Lifecycle Methods class Clock extends React.Component { constructor(props) { ... } componentDidMount() { ... } componentWillUnmount() { clearInterval(this.timerId); } render() { ... } } 63
  • 64. setState Asynchronous // Wrong! setState({counter: this.state.counter + 1}); // Correct setState((prevState, props) => ({ counter: prevState.counter + 1 }); 64
  • 65. States are Merged constructor() { this.state = {posts: [], users: []}; } componentDidMount() { getPosts((posts) => this.setState({posts})); getUsers((users) => this.setState({users})); } 65
  • 66. State Isolated function App() { return ( <div> <Clock /> <Clock /> <Clock /> </div> ); } 66
  • 68. onEvent={fn} function ButtonLogHello() { function handleClick() { console.log('The button is clicked'); } return ( <button onClick={handleClick}> click me </button> ); } 68
  • 69. onEvent={fn} // It received the event as parameter function ALogHello() { function handleClick(ev) { ev.preventDefault(); console.log('The link is clicked'); } return ( <a href="#" onClick={handleClick}> click me </a> ); } 69
  • 70. onEvent={fn} // It can inline functions (are expressions) function DivLogHello() { return ( <button onClick={() => console.log('oh')}> click me </button> ); } 70
  • 71. Toggle Example class Toggle extends React.Component { constructor(props) { super(props); this.state = { isToggleOn: true }; } ... 71
  • 72. Toggle Example class Toggle extends React.Component { constructor(props) { super(props); this.state = { isToggleOn: true }; } handleClick() { ... } ... 72
  • 73. Toggle Example class Toggle extends React.Component { constructor(props) { super(props); this.state = { isToggleOn: true }; // This binding is necessary by `this` this.handleClick = this.handleClick.bind(this); } handleClick() { ... } ... 73
  • 74. Toggle Example class Toggle extends React.Component { constructor(props) { super(props); this.state = { isToggleOn: true }; // Fat arrow function preserves `this` this.handleClick = () => { ... }; } ... 74
  • 75. Toggle Example class Toggle extends React.Component { constructor(props) { super(props); this.state = { isToggleOn: true }; } // Stage 2 alternative (recommended official) handleClick = () => { ... } ... 75
  • 76. Toggle Example class Toggle extends React.Component { constructor(props) { super(props); this.state = { isToggleOn: true }; } handleClick = () => { … } render() { return ( <button onClick={this.handleClick}> {this.state.isToggleOn ? 'on' : 'off'} </button> ); } } 76
  • 77. Toggle Example class Toggle extends React.Component { constructor(props) { super(props); this.state = { isToggleOn: true }; } handleClick = () => { // Warning, wrong implementation this.setState({ isToggleOn: !this.state.isToggleOn }); } render() { return ( <button onClick={this.handleClick}> {this.state.isToggleOn ? 'on' : 'off'} </button> ); } } 77
  • 78. Toggle Example class Toggle extends React.Component { constructor(props) { super(props); this.state = { isToggleOn: true }; } handleClick = () => { this.setState((prevState) => ({ isToggleOn: !prevState.isToggleOn, }); } render() { return ( <button onClick={this.handleClick}> {this.state.isToggleOn ? 'on' : 'off'} </button> ); } } 78
  • 80. Conditional Rendering function UserGreeting(props) { return <h1>Welcome back!</h1>; } function GuestGreeting(props) { return <h1>Please sign up.</h1>; } 80
  • 81. By return function Greeting(props) { const isLoggedIn = props.isLoggedIn; if (isLoggedIn) { return <UserGreeting />; } return <GuestGreeting />; } ReactDOM.render( // Try changing to isLoggedIn={true}: <Greeting isLoggedIn={false} />, document.getElementById('root') ); 81
  • 82. By variable render() { const isLoggedIn = this.state.isLoggedIn; let button = null; if (isLoggedIn) { button = <LogoutButton onClick={this.handleLogoutClick} / >; } else { button = <LoginButton onClick={this.handleLoginClick} />; } return ( <div> <Greeting isLoggedIn={isLoggedIn} /> {button} </div> ); } 82
  • 83. By && expression function Mailbox(props) { const unreadMessages = props.unreadMessages; return ( <div> <h1>Hello!</h1> {unreadMessages.length > 0 && <h2> You have {unreadMessages.length} unread messages. </h2> } </div> ); } 83
  • 84. By ?: expression render() { const isLoggedIn = this.state.isLoggedIn; return ( <div> {isLoggedIn ? ( <LogoutButton onClick={this.handleLogoutClick} /> ) : ( <LoginButton onClick={this.handleLoginClick} /> )} </div> ); } 84
  • 85. Prevent Render function WarningBanner(props) { if (!props.warn) { return null; } return ( <div className="warning"> Warning! </div> ); } 85
  • 87. Remember... const numbers = [1, 2, 3, 4, 5]; const doubled = numbers.map((n) => n * 2); console.log(doubled); // [2, 4, 6, 8, 10] 87
  • 88. Render Multiple // Render a reactElements array const numbers = [1, 2, 3, 4, 5]; const listItems = numbers.map((number) => <li>{number}</li> ); ReactDOM.render( <ul>{listItems}</ul>, document.getElementById('root') ); 88
  • 89. Render Multiple // Refactor into component function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => <li>{number}</li> ); return ( <ul>{listItems}</ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers} />, document.getElementById('root') ); 89
  • 90. Key function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li> ); return ( <ul>{listItems}</ul> ); } 90
  • 91. Key - index const todoItems = todos.map((todo, index) => // Only do this if items have no stable IDs <li key={index}> {todo.text} </li> ); 91
  • 92. Key - Refactor Component function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li> ); return ( <ul>{listItems}</ul> ); } 92
  • 93. Key - Refactor Component function ListItem(props) { return ( // Wrong! should not be here <li key="props.number.toString()"> {props.number} </li> ); } 93
  • 94. Key - Refactor Component function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => // Correct: key must remain with map <ListItem key={number.toString()} number={number} /> {number} ); return ( <ul>{listItems}</ul> ); } 94
  • 95. Key - Uniqueness // Cannot repeat keys in the same list, but... function DoubleList(props) { return ( <div> <NumberList numbers={props.numbers} /> <NumberList numbers={props.numbers} /> <NumberList numbers={props.numbers} /> </div> ); } 95
  • 96. .map inside JSX function NumberList(props) { const numbers = props.numbers; return ( <ul> {numbers.map((number) => <ListItem key={number.toString()} value={number} /> )} </ul> ); } 96
  • 98. Controlled Components class NameForm extends React.Component { constructor() { ... } handleChange = (event) => { this.setState({value: event.target.value}); } handleSubmit = (event) => { ... } render() { return ( <form onSubmit={this.handleSubmit}> <input type="text" value={this.state.value} onChange={this.handleChange} /> </form> ); } } 98
  • 99. Controlled Components class NameForm extends React.Component { constructor(props) { super(props); this.state = {value: ''}; } handleChange = (event) => { ... } handleSubmit = (event) => { ... } render() { ... } } 99
  • 100. Controlled Components class NameForm extends React.Component { constructor() { ... } handleChange = (event) => { this.setState({ value: event.target.value.toLowerCase() }); } handleSubmit = (event) => { ... } render() { ... } } 100
  • 103. Multiple Inputs <input name="isGoing" type="checkbox" checked={this.state.isGoing} onChange={this.handleInputChange} /> <input name="numberOfGuests" type="number" value={this.state.numberOfGuests} onChange={this.handleInputChange} /> 103
  • 104. Multiple Inputs handleInputChange(event) { const target = event.target; const value = target.type === 'checkbox' ? target.checked : target.value; const name = target.name; this.setState({ [name]: value }); } 104
  • 106. Synchronizing - Consumer // We want an <input> to generate new values for function BoilingVerdict(props) { if (props.celsius >= 100) { return <p>The water would boil.</p>; } return <p>The water would not boil.</p>; } 106
  • 107. Synchronizing - Coordinator class Calculator extends React.Component { constructor(props) { ... } handleChange = (e) => this.setState({temperature: e.target.value}); render() { const temperature = this.state.temperature; return ( <fieldset> <legend>Enter temperature in Celsius:</legend> <input value={temperature} onChange={this.handleChange} /> <BoilingVerdict celsius={parseFloat(temperature)} /> </fieldset> ); } } 107
  • 108. Synchronizing - Producer class Calculator extends React.Component { constructor(props) { ... } handleChange = (e) => this.setState({temperature: e.target.value}); render() { const temperature = this.state.temperature; return ( <fieldset> <legend>Enter temperature in Celsius:</legend> <input value={temperature} onChange={this.handleChange} /> <BoilingVerdict celsius={parseFloat(temperature)} /> </fieldset> ); } } 108
  • 109. Synchronizing - Producer class TemperatureInputCelsius extends React.Component { constructor(props) { ... } render() { const temperature = this.state.temperature; return ( <fieldset> <legend>Enter temperature in Celsius:</legend> <input value={temperature} onChange={this.handleChange} /> </fieldset> ); } } 109
  • 110. Synchronizing - Producer class TemperatureInputCelsius extends React.Component { constructor(props) { ... } handleChange render() { const temperature = this.state.temperature; return ( <fieldset> <legend>Enter temperature in Celsius:</legend> <input value={temperature} onChange={this.handleChange} /> </fieldset> ); } } 110
  • 111. Synchronizing - Producer class TemperatureInputCelsius extends React.Component { constructor(props) { ... } handleChange = (e) => this.setState({temperature: e.target.value}); render() { const temperature = this.state.temperature; return ( <fieldset> <legend>Enter temperature in Celsius:</legend> <input value={temperature} onChange={this.handleChange} /> </fieldset> ); } } 111
  • 112. Synchronizing - Producer class TemperatureInputCelsius extends React.Component { constructor(props) { ... } handleChange = (e) => this.setState({temperature: e.target.value}); render() { const temperature = this.state.temperature; return ( <fieldset> <legend>Enter temperature in Celsius:</legend> <input value={temperature} onChange={this.handleChange} /> </fieldset> ); } } 112
  • 113. Synchronizing - Coordinator class Calculator extends React.Component { constructor(props) { ... } handleChange = (...?) => this.setState({temperature: ...?}); render() { const temperature = this.state.temperature; return ( <TemperatureInputCelsius ...? ...? /> <BoilingVerdict celsius={parseFloat(temperature)} /> </fieldset> ); } } 113
  • 114. Synchronizing - Coordinator class Calculator extends React.Component { constructor(props) { ... } handleChange = (temperature) => this.setState({temperature: temperature}); render() { const temperature = this.state.temperature; return ( <TemperatureInputCelsius temperature={temperature} onTemperatureChange={this.handleChange} /> <BoilingVerdict celsius={parseFloat(temperature)} /> </fieldset> ); } } 114
  • 115. Synchronizing - Producer class TemperatureInputCelsius extends React.Component { constructor(props) { ... } handleChange = (e) => this.setState({temperature: e.target.value}); render() { const temperature = this.state.temperature; return ( <fieldset> <legend>Enter temperature in Celsius:</legend> <input value={temperature} onChange={this.handleChange} /> </fieldset> ); } } 115
  • 116. Synchronizing - Producer class TemperatureInputCelsius extends React.Component { constructor(props) { ... } handleChange = (e) => this.props.onTemperatureChange(e.target.value); render() { const temperature = this.props.temperature; return ( <fieldset> <legend>Enter temperature in Celsius:</legend> <input value={temperature} onChange={this.handleChange} /> </fieldset> ); } } 116
  • 117. Synchronizing - Coordinator 117 Calculator this: { handleChange } state: { temperature } props: { temperature } BoilingVeredict props: { temperature, onTemperatureChange } TemperatureInputCelsius
  • 118. Synchronizing - Multiple Producer Calculator TemperatureInput => Celsius and Fahrenheit 118
  • 119. Synchronizing - Producer class TemperatureInput extends React.Component { constructor(props) { ... } handleChange = (e) => this.setState({temperature: e.target.value}); render() { const temperature = this.state.temperature; const scaleName = scaleNames[this.props.scale]; return ( <fieldset> <legend>Enter temperature in {scaleName}:</ legend> <input value={temperature} onChange={this.handleChange} /> </fieldset> ); } } 119
  • 120. Synchronizing - Producer class Calculator extends React.Component { constructor(props) { ... } handleChange = (e) => this.setState({temperature: ...?}); render() { const temperature = this.state.temperature; return ( <div> <TemperatureInput scale="c" ...? ...? /> <TemperatureInput scale="f" ...? ...? /> <BoilingVerdict celsius={parseFloat(temperature)} /> </div> ); } } 120
  • 121. Synchronizing - Producer class TemperatureInput extends React.Component { constructor(props) { ... } handleChange = (e) => this.props.onTemperatureChange(e.target.value); render() { const temperature = this.props.temperature; const scaleName = scaleNames[this.props.scale]; return ( <fieldset> <legend>Enter temperature in {scaleName}:</ legend> <input value={temperature} onChange={this.handleChange} /> </fieldset> ); } } 121
  • 122. Synchronizing - Coordinator class Calculator extends React.Component { constructor(props) { ... } handleChange = (e) => this.setState({temperature: ...?}); render() { const temperature = this.state.temperature; return ( <div> <TemperatureInput scale="c" ...? ...? /> <TemperatureInput scale="f" ...? ...? /> <BoilingVerdict celsius={parseFloat(temperature)} /> </div> ); } } 122
  • 123. Coordinator - Inputs class Calculator extends React.Component { ... render() { const scale = this.state.scale; const temperature = this.state.temperature; const celsius = convertIf(scale === 'f', temperature, toCelsius); const fahrenheit = convertIf(scale === 'c', temperature, toFahrenheit); return ( <div> <TemperatureInput scale="c" temperature={celsius} ...? /> <TemperatureInput scale="f" temperature={fahrenheit} ...? /> <BoilingVerdict celsius={parseFloat(celsius)} /> </div> ); } } 123
  • 124. Coordinator Outputs class Calculator extends React.Component { ... handleCelsiusChange = (temperature) => this.setState({scale: 'c', temperature}); handleFahrenheitChange = (temperature) => this.setState({scale: 'f', temperature}); render() { const scale = this.state.scale; const temperature = this.state.temperature; const celsius = convertIf(scale === 'f', temperature, toCelsius); ... <TemperatureInput scale="c" temperature={celsius} onTemperatureChange={this.handleCelsiusChange} /> <TemperatureInput scale="f" temperature={fahrenheit} onTemperatureChange={this.handleFahrenheitChange} /> ... } } 124
  • 125. Coordinator Outputs function convertIf(test, temperature, convert) { if (test) { return tryConvert(temperature, convert); } return temperature; } 125
  • 128. Java 1.0 128 http://web.mit.edu/java_v1.0.2/www/apibook/javag2.htm An application should override the action method (II- §1.10.1) of the button or of one of its containing windows in order to cause some action to occur. Button + action(...) MyButton + action(...)
  • 129. Java 1.1 129 In 1.1, we aimed at solving some major AWT (Abstract Window Toolkit) deficiencies, with a strong focus on quality and performance. The AWT enhancements include [...], a delegation-based event model, [...]. Button + actionActionListener(...) https://www.cs.princeton.edu/courses/archive/fall97/cs461/ jdkdocs/guide/awt/index.html <i> ActionListener + actionPerformed(...) = 0 MyActionListener + actionPerformed(...) *
  • 130. Java 1.2 130 When an Action object is added to such a container, the container: Creates a component that is appropriate for that container (a toolbar creates a button component, for example), Gets the appropriate property(s) from the Action object to customize the component (for example, the icon image and flyover text).... <i> Action + actionPerformed(...) = 0 + isEnabled(): bool + setEnabled(b) + getValue(key): Object + putValue(key, value) + addPropertyChangeListener(...) + removePropertyChangeListener(...) http://www.kbs.twi.tudelft.nl/Documentation/Programming/ Java/jdk1.2/api/javax/swing/Action.html
  • 132. Children Composition <Card> <h1>Welcome</h1> <p> Find here a complete list of all the things that you love. </p> </Card> 132
  • 133. Children Composition function Card(props) { return ( <div className="card"> {props.children} </div> ); } 133
  • 135. Many Children Composition <div class="SplitPane"> <div class="SplitPane-left"> <Contacts /> </div> <div class="SplitPane-right"> <Chat /> </div> </div> 135
  • 136. Many Children Composition function SplitPane(props) { return ( <div className="SplitPane"> <div className="SplitPane-left"> {props.left} </div> <div className="SplitPane-right"> {props.right} </div> </div> ); } 136
  • 137. Many Children Composition function App() { return ( <SplitPane left={ <Contacts /> } right={ <Chat /> } /> ); } 137
  • 138. Specialization function Dialog(props) { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> {props.title} </h1> <p className="Dialog-message"> {props.message} </p> </FancyBorder> ); } 138
  • 139. Specialization function WelcomeDialog(props) { return ( <Dialog title="Welcome" message="Thanks for visiting!" /> ); } 139
  • 140. Specialization function WelcomeDialog(props) { return ( <Dialog title="Welcome" message={ <div> <h1>Thanks!</h1> for visiting! </div> } /> ); } 140
  • 142. Like high order functions const safeConvert = (convert) => { return (temperature) => { const input = parseFloat(temperature); if (Number.isNaN(input)) { return ''; } const output = convert(input); const rounded = Math.round(output * 100) / 100; return rounded.toString(); } } 142
  • 143. Like high order functions const safeConvert = (convert) => { return (temperature) => { ... } } const safeKelvinToCelsius = safeConvert(kelvinToCelsius); const celsius = safeKelvinToCelsius(kelvin); 143
  • 144. Specific Component class TemperatureInputCelsius extends React.Component { handleChange = (e) => this.props.onTemperatureChange( safeCelsiusToKelvin(e.target.value); ); render() { const temperature = this.props.temperature; const celsius = safeKelvinToCelsius(temperature); return ( <fieldset> <legend>Enter temperature in Celsius:</legend> <input value={temperature} onChange={this.handleChange} /> </fieldset> ); } } 144
  • 145. Specific Component class TemperatureInputFahrenheit extends React.Component { handleChange = (e) => this.props.onTemperatureChange( safeFahrenheitToKelvin(e.target.value); ); render() { const temperature = this.props.temperature; const celsius = safeKelvinToFahrenheit(temperature); return ( <fieldset> <legend>Enter temperature in Fahrenheit:</legend> <input value={temperature} onChange={this.handleChange} /> </fieldset> ); } } 145
  • 146. Generic Component class TemperatureInput? extends React.Component { handleChange = (e) => this.props.onTemperatureChange( toKelvin(e.target.value); ); render() { const temperature = this.props.temperature; const local = toLocal(temperature); return ( <fieldset> <legend>Enter temperature in {scaleName}:</ legend> <input value={local} onChange={this.handleChange} /> </fieldset> ); } } 146
  • 147. Generic Component function makeTemperatureInput(toKelvin, toLocal, scaleName) { return class extends React.Component { handleChange = (e) => this.props.onTemperatureChange( toKelvin(e.target.value); ); render() { const temperature = this.props.temperature; const local = toLocal(temperature); return ( <fieldset> <legend>Enter temperature in {scaleName}:</legend> <input value={local} onChange={this.handleChange} /> </fieldset> ); } } } 147
  • 148. Using Generic Component const TemperatureInputCelsius = makeTemperatureInput( safeCelsiusToKelvin, safeKelvinToCelsius, 'Celsius' ); const TemperatureInputFahrenheit = makeTemperatureInput( safeFahrenheitToKelvin, safeKelvinToFahrenheit, 'Fahrenheit' ); const TemperatureInputKelvin = makeTemperatureInput( identity, identity, 'Kelvin' ); 148
  • 149. Using Generic Component const TemperatureInputCelsius = makeTemperatureInput( safeConvert(celsiusToKelvin), safeConvert(kelvinToCelsius), 'Celsius' ); const TemperatureInputFahrenheit = makeTemperatureInput( safeConvert(fahrenheitToKelvin), safeConvert(kelvinToFahrenheit), 'Fahrenheit' ); const TemperatureInputKelvin = makeTemperatureInput( (x) => x, (x) => x, 'Kelvin' ); 149
  • 150. High Order Component class Thermostat extends React.Component { constructor(props) { ... } handleChangeMax = (e) => ... handleChangeMin = (e) => ... render() { return ( <div> Max <TemperatureInput temperature={this.state.max} onTemperatureChange={this.handleChangeMax} /> Min <TemperatureInput temperature={this.state.min} onTemperatureChange={this.handleChangeMin} /> </div> ); } } 150
  • 151. High Order Component function makeThermostat(TemperatureInput) { return class extends React.Component { constructor(props) { ... } handleChangeMax = (e) => ... handleChangeMin = (e) => ... render() { return ( <div> Max <TemperatureInput temperature={this.state.max} onTemperatureChange={this.handleChangeMax} /> Min <TemperatureInput temperature={this.state.max} onTemperatureChange={this.handleChangeMax} /> </div> ); } } } 151
  • 152. High Order Component function makeThermostat(TemperatureInput) { return class extends React.Component { ... } } const ThermostatCelsius = makeThermostat(TemperatureInputCelsius); const ThermostatFahrenheit = makeThermostat(TemperatureInputFahrenheit); const ThermostatKelvin = makeThermostat(TemperatureInputKelvin); 152
  • 153. Debug: displayName function makeTemperatureInput( toKelvin, toFahrenheit, scaleName ) { class TemperatureInput extends React.Component { ... } TemperatureInput.displayName = `TemperatureInput(${scaleName})`; return TemperatureInput; } 153
  • 154. Debug: displayName function makeThermostat(TemperatureInput) { class Thermostat extends React.Component { ... } Thermostat.displayName = `Thermostat(${getDisplayName(TemperatureInput)})`; return Thermostat; } 154
  • 155. Warning! // DON'T use HOCs in render functions! const App = () => { const TemperatureInputAbc = makeTemperatureInput(a, b, c); return <TemperatureInputAbc />; } class App extends React.Component { render() { const TemperatureInputAbc = makeTemperatureInput(a, b, c); return <TemperatureInputAbc />; } } 155
  • 156. More in docs • Use HOCs For Cross-Cutting Concerns • Don't Mutate the Original Component. 
 Use Composition. • Convention: Pass Unrelated Props Through to the Wrapped Component • Convention: Maximizing Composability • Convention: Wrap the Display Name for Easy Debugging • Caveats 156
  • 158. Convention • Types of components • Routers • Containers • Presentational 158
  • 159. Routes • Routers • Decides which component to render • Create components dynamically • Usually provided by library 159
  • 160. Containers • Knows how to load or mutate data • Observe Stores • Dispatch Actions • Other system interactions • Always stateful (class notation) • Renders nothing • Delegates render to a Presentational Component • Configures its props 160
  • 161. Presentational • Knows how to render things • Data and callbacks only via props • does not interact with the application • Usually functional (not need state) • Also called Components 161
  • 162. class Clock extends React.Component { constructor(props) { ... } componentDidMount() { this.timerId = setInterval( () => this.setState({time: Date.now()}), 1000 ); } componentWillUnmount() { clearInterval(this.timerId); } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.time}.</h2> </div> ); } } 162 Presentational Container
  • 163. class Clock extends React.Component { constructor(props) { ... } componentDidMount() { this.timerId = setInterval( () => this.setState({time: Date.now()}), 1000 ); } componentWillUnmount() { clearInterval(this.timerId); } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.time}.</h2> </div> ); } } 163 Presentational Container
  • 164. Presentational Refactor function Clock(props) { return ( <div> <h1>Hello, world!</h1> <h2>It is {props.time}.</h2> </div> ); } 164
  • 165. Container Refactor class IntervalClock extends React.Component { constructor(props) { ... } componentDidMount() { this.timerId = setInterval( () => this.setState({time: Date.now()}), 1000 ); } componentWillUnmount() { clearInterval(this.timerId); } render() { return <Clock time={this.state.time} />; } } 165
  • 166. Container Refactor function makeIntervalClock(Clock) { return class extends React.Component { constructor(props) { ... } componentDidMount() { this.timerId = setInterval( () => this.setState({time: Date.now()}), 1000 ); } componentWillUnmount() { clearInterval(this.timerId); } render() { return <Clock time={this.state.time} />; } }; } 166
  • 168. PropTypes import PropTypes from 'prop-types'; export default function Welcome(props) { return ( <h1>Hello, {props.name}</h1> ); } Welcome.propTypes = { name: PropTypes.string }; 168 https://facebook.github.io/react/docs/typechecking-with-proptypes.html
  • 169. PropTypes import PropTypes from 'prop-types'; export default class Welcome extends React.Component { render() { return ( <h1>Hello, {this.props.name}</h1> ); } } Welcome.propTypes = { name: PropTypes.string.isRequired }; 169 https://facebook.github.io/react/docs/typechecking-with-proptypes.html