Fullstack React Fullstack.React.The..Guide.to.React JS.and.Friends

User Manual:

Open the PDF directly: View PDF PDF.
Page Count: 825

DownloadFullstack React Fullstack.React.The..Guide.to.React JS.and.Friends
Open PDF In BrowserView PDF
Sold to
vpicone@gmail.com

Fullstack React
The Complete Guide to ReactJS and Friends

Written by Anthony Accomazzo, Ari Lerner, Nate Murray, Clay Allsopp, David
Guttman, and Tyler McGinnis
Technical Advisor: Sophia Shoemaker
© 2017 Fullstack.io
All rights reserved. No portion of the book manuscript may be reproduced, stored in a retrieval
system, or transmitted in any form or by any means beyond the number of purchased copies,
except for a single backup or archival copy. The code may be used freely in your projects,
commercial or otherwise.
The authors and publisher have taken care in preparation of this book, but make no expressed
or implied warranty of any kind and assume no responsibility for errors or omissions. No
liability is assumed for incidental or consequential damagers in connection with or arising out
of the use of the information or programs container herein.
Typeset using Leanpub.
Published in San Francisco, California by Fullstack.io.

FULLSTACK .io

Contents
Book Revision . . . . . . . . . .
Bug Reports . . . . . . . . . . .
Chat With The Community! . .
Be notified of updates via Twitter
We’d love to hear from you! . . .

.
.
.
.
.

1
1
1
1
1

Foreword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2

How to Get the Most Out of This Book
Overview . . . . . . . . . . . . . . .
Running Code Examples . . . . . .
Project setups . . . . . . . . . . .
Code Blocks and Context . . . . . .
Code Block Numbering . . . . .
Getting Help . . . . . . . . . . . . .
Emailing Us . . . . . . . . . . . . .
Technical Support Response Time
Get excited . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.

1
1
2
2
3
3
3
4
5
5

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6

Part I

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

Your first React Web Application . . . . . .
Building Product Hunt . . . . . . . . . . .
Setting up your development environment
Code editor . . . . . . . . . . . . . . .
Node.js and npm . . . . . . . . . . . .
Install Git . . . . . . . . . . . . . . . .
Browser . . . . . . . . . . . . . . . . .
Special instruction for Windows users . .
Ensure IIS is installed . . . . . . . . . .
JavaScript ES6/ES7 . . . . . . . . . . . . .
Getting started . . . . . . . . . . . . . . .
Sample Code . . . . . . . . . . . . . .

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

7
7
7
7
7
8
8
8
8
8
9
9

CONTENTS

Previewing the application . . . . . . . . . . . . . . . . . . . .
Prepare the app . . . . . . . . . . . . . . . . . . . . . . . . . .
What’s a component? . . . . . . . . . . . . . . . . . . . . . . . .
Our first component . . . . . . . . . . . . . . . . . . . . . . .
JSX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
The developer console . . . . . . . . . . . . . . . . . . . . . .
Babel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
ReactDOM.render() . . . . . . . . . . . . . . . . . . . . . . .
Building Product . . . . . . . . . . . . . . . . . . . . . . . . . .
Making Product data-driven . . . . . . . . . . . . . . . . . . . .
The data model . . . . . . . . . . . . . . . . . . . . . . . . . .
Using props . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Rendering multiple products . . . . . . . . . . . . . . . . . . .
React the vote (your app’s first interaction) . . . . . . . . . . . .
Propagating the event . . . . . . . . . . . . . . . . . . . . . .
Binding custom component methods . . . . . . . . . . . . . .
Using state . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Setting state with this.setState() . . . . . . . . . . . . . . .
Updating state and immutability . . . . . . . . . . . . . . . . . .
Refactoring with the Babel plugin transform-class-properties
Babel plugins and presets . . . . . . . . . . . . . . . . . . . .
Property initializers . . . . . . . . . . . . . . . . . . . . . . . .
Refactoring Product . . . . . . . . . . . . . . . . . . . . . . .
Refactoring ProductList . . . . . . . . . . . . . . . . . . . . .
Congratulations! . . . . . . . . . . . . . . . . . . . . . . . . . . .
Components . . . . . . . . . . . . . . . . . . . . .
A time-logging app . . . . . . . . . . . . . . .
Getting started . . . . . . . . . . . . . . . . . .
Previewing the app . . . . . . . . . . . . . .
Prepare the app . . . . . . . . . . . . . . . .
Breaking the app into components . . . . . . .
The steps for building React apps from scratch .
Step 2: Build a static version of the app . . . . .
TimersDashboard . . . . . . . . . . . . . . .
EditableTimer . . . . . . . . . . . . . . . .
TimerForm . . . . . . . . . . . . . . . . . . .
ToggleableTimerForm . . . . . . . . . . . .
Timer . . . . . . . . . . . . . . . . . . . . .
Render the app . . . . . . . . . . . . . . . .
Try it out . . . . . . . . . . . . . . . . . . .
Step 3: Determine what should be stateful . . .
State criteria . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

9
11
15
16
18
19
21
23
25
27
28
28
32
37
37
39
42
44
46
51
51
52
53
54
56

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

57
57
58
58
58
62
69
71
71
73
74
75
76
77
78
79
79

CONTENTS

Applying the criteria . . . . . . . . . . . . . . . . . . . . . . . . .
Step 4: Determine in which component each piece of state should live
The list of timers and properties of each timer . . . . . . . . . . .
Whether or not the edit form of a timer is open . . . . . . . . . .
Visibility of the create form . . . . . . . . . . . . . . . . . . . . .
Step 5: Hard-code initial states . . . . . . . . . . . . . . . . . . . . .
Adding state to TimersDashboard . . . . . . . . . . . . . . . . . .
Receiving props in EditableTimerList . . . . . . . . . . . . . . .
Props vs. state . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Adding state to EditableTimer . . . . . . . . . . . . . . . . . . .
Timer remains stateless . . . . . . . . . . . . . . . . . . . . . . . .
Adding state to ToggleableTimerForm . . . . . . . . . . . . . . .
Adding state to TimerForm . . . . . . . . . . . . . . . . . . . . . .
Step 6: Add inverse data flow . . . . . . . . . . . . . . . . . . . . . .
TimerForm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
ToggleableTimerForm . . . . . . . . . . . . . . . . . . . . . . . .
TimersDashboard . . . . . . . . . . . . . . . . . . . . . . . . . . .
Updating timers . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Adding editability to Timer . . . . . . . . . . . . . . . . . . . . .
Updating EditableTimer . . . . . . . . . . . . . . . . . . . . . . .
Updating EditableTimerList . . . . . . . . . . . . . . . . . . . .
Defining onEditFormSubmit() in TimersDashboard . . . . . . . .
Deleting timers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Adding the event handler to Timer . . . . . . . . . . . . . . . . .
Routing through EditableTimer . . . . . . . . . . . . . . . . . . .
Routing through EditableTimerList . . . . . . . . . . . . . . . .
Implementing the delete function in TimersDashboard . . . . . . .
Adding timing functionality . . . . . . . . . . . . . . . . . . . . . . .
Adding a forceUpdate() interval to Timer . . . . . . . . . . . . .
Try it out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Add start and stop functionality . . . . . . . . . . . . . . . . . . . .
Add timer action events to Timer . . . . . . . . . . . . . . . . . .
Create TimerActionButton . . . . . . . . . . . . . . . . . . . . . .
Run the events through EditableTimer and EditableTimerList .
Try it out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Methodology review . . . . . . . . . . . . . . . . . . . . . . . . . . .
Components & Servers . .
Introduction . . . . . .
Preparation . . . . .
server.js . . . . . . .
The Server API . . . . .
text/html endpoint

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

80
81
82
82
82
83
83
84
85
85
86
86
88
91
92
93
95
97
97
98
100
100
103
103
104
104
105
106
107
108
108
108
109
110
113
114

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

116
116
116
116
117
118

CONTENTS

JSON endpoints . . . . . . . . . . . . . . . . . .
Playing with the API . . . . . . . . . . . . . . . .
Loading state from the server . . . . . . . . . . . .
Try it out . . . . . . . . . . . . . . . . . . . . .
client . . . . . . . . . . . . . . . . . . . . . . . .
Fetch . . . . . . . . . . . . . . . . . . . . . . .
Sending starts and stops to the server . . . . . . . .
Sending creates, updates, and deletes to the server .
Give it a spin . . . . . . . . . . . . . . . . . . .
Next up . . . . . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

118
119
122
125
125
126
129
131
133
133

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

134
134
134
134
135
136
136
138
140
141
142
142
144
144
145
145
145
146
149
150

Advanced Component Configuration with props, state, and children
Intro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
How to use this chapter . . . . . . . . . . . . . . . . . . . . . . . . .
ReactComponent . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Creating ReactComponents - createClass or ES6 Classes . . . . .
render() Returns a ReactElement Tree . . . . . . . . . . . . . . .
Getting Data into render() . . . . . . . . . . . . . . . . . . . . .
props are the parameters . . . . . . . . . . . . . . . . . . . . . . . .
PropTypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Default props with getDefaultProps() . . . . . . . . . . . . . . . .
context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

151
151
152
152
152
153
154
155
156
158
158

JSX and the Virtual DOM . . . . . . . . .
React Uses a Virtual DOM . . . . . . .
Why Not Modify the Actual DOM? .
What is a Virtual DOM? . . . . . . . .
Virtual DOM Pieces . . . . . . . . . .
ReactElement . . . . . . . . . . . . .
Experimenting with ReactElement
Rendering Our ReactElement . . .
Adding Text (with children) . . . .
ReactDOM.render() . . . . . . . .
JSX . . . . . . . . . . . . . . . . . . .
JSX Creates Elements . . . . . . . .
JSX Attribute Expressions . . . . .
JSX Conditional Child Expressions
JSX Boolean Attributes . . . . . . .
JSX Comments . . . . . . . . . . .
JSX Spread Syntax . . . . . . . . .
JSX Gotchas . . . . . . . . . . . . .
JSX Summary . . . . . . . . . . . .
References . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

CONTENTS

state . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
Using state: Building a Custom Radio Button . . . . . . . . . . . . . . . . . . . . . . 164

Stateful components . . . . . . . . . . . . . . . . . . .
State updates that depend on the current state . . . . .
Thinking About State . . . . . . . . . . . . . . . . . . .
Stateless Components . . . . . . . . . . . . . . . . . . . .
Switching to Stateless . . . . . . . . . . . . . . . . . .
Stateless Encourages Reuse . . . . . . . . . . . . . . . .
Talking to Children Components with props.children . .
React.Children.map() & React.Children.forEach()
React.Children.toArray() . . . . . . . . . . . . . . .
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . .
References . . . . . . . . . . . . . . . . . . . . . . . . . .
Forms . . . . . . . . . . . . . . . . . . . . . . .
Forms 101 . . . . . . . . . . . . . . . . . .
Preparation . . . . . . . . . . . . . . . .
The Basic Button . . . . . . . . . . . . .
Events and Event Handlers . . . . . . . .
Back to the Button . . . . . . . . . . . .
Text Input . . . . . . . . . . . . . . . . . .
Accessing User Input With refs . . . . .
Using User Input . . . . . . . . . . . . .
Uncontrolled vs. Controlled Components
Accessing User Input With state . . . .
Multiple Fields . . . . . . . . . . . . . .
On Validation . . . . . . . . . . . . . . .
Adding Validation to Our App . . . . . .
Creating the Field Component . . . . . .
Using our new Field Component . . . .
Remote Data . . . . . . . . . . . . . . . . .
Building the Custom Component . . . .
Adding CourseSelect . . . . . . . . . . .
Separation of View and State . . . . . .
Async Persistence . . . . . . . . . . . . . .
Redux . . . . . . . . . . . . . . . . . . . . .
Form Component . . . . . . . . . . . . .
Connect the Store . . . . . . . . . . . . .
Form Modules . . . . . . . . . . . . . . . .
formsy-react . . . . . . . . . . . . . . .
react-input-enhancements . . . . . . . .
tcomb-form . . . . . . . . . . . . . . . .
winterfell . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

169
171
173
174
175
177
177
180
181
182
182

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

183
183
183
184
186
187
189
189
191
194
195
197
202
202
206
210
215
215
221
224
224
231
236
240
242
242
242
243
243

CONTENTS

react-redux-form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
Using Webpack with Create React App . . . .
JavaScript modules . . . . . . . . . . . .
Create React App . . . . . . . . . . . . .
Exploring Create React App . . . . . . . . .
public/index.html . . . . . . . . . . .
package.json . . . . . . . . . . . . . . .
src/ . . . . . . . . . . . . . . . . . . . .
index.js . . . . . . . . . . . . . . . . .
Booting the app . . . . . . . . . . . . . .
Webpack basics . . . . . . . . . . . . . . .
Making modifications to the sample app . .
Hot reloading . . . . . . . . . . . . . . .
Auto-reloading . . . . . . . . . . . . . .
Creating a production build . . . . . . . . .
Ejecting . . . . . . . . . . . . . . . . . . . .
Buckle up . . . . . . . . . . . . . . . . .
Using Create React App with an API server
The completed app . . . . . . . . . . . .
How the app is organized . . . . . . . .
The server . . . . . . . . . . . . . . . . .
Client . . . . . . . . . . . . . . . . . . .
Concurrently . . . . . . . . . . . . . . .
Using the Webpack development proxy .
Webpack at large . . . . . . . . . . . . . . .
When to use Webpack/Create React App

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

244
244
246
247
248
249
251
253
255
256
262
262
263
264
267
268
270
270
274
275
276
277
280
282
283

Unit Testing . . . . . . . . . . . . . . . . .
Writing tests without a framework . . .
Preparing Modash . . . . . . . . . . .
Writing the first spec . . . . . . . . .
The assertEqual() function . . . . .
What is Jest? . . . . . . . . . . . . . . .
Using Jest . . . . . . . . . . . . . . . . .
expect() . . . . . . . . . . . . . . .
The first Jest test for Modash . . . . .
The other truncate() spec . . . . . .
The rest of the specs . . . . . . . . .
Testing strategies for React applications
Integration vs Unit Testing . . . . . .
Shallow rendering . . . . . . . . . .
Enzyme . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

284
284
285
288
290
294
294
295
297
299
300
302
302
303
303

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

CONTENTS

Testing a basic React component with Enzyme .
Setup . . . . . . . . . . . . . . . . . . . . . .
The App component . . . . . . . . . . . . . . .
The first spec for App . . . . . . . . . . . . . .
More assertions for App . . . . . . . . . . . . .
Using beforeEach . . . . . . . . . . . . . . .
Simulating a change . . . . . . . . . . . . . .
Clearing the input field . . . . . . . . . . . . .
Simulating a form submission . . . . . . . . .
Writing tests for the food lookup app . . . . . . .
FoodSearch . . . . . . . . . . . . . . . . . . .
Exploring FoodSearch . . . . . . . . . . . . .
Writing FoodSearch.test.js . . . . . . . . . . .
In initial state . . . . . . . . . . . . . . . . . .
A user has typed a value into the search field .
Mocking with Jest . . . . . . . . . . . . . . .
Mocking Client . . . . . . . . . . . . . . . .
The API returns results . . . . . . . . . . . . .
The user clicks on a food item . . . . . . . . .
The API returns empty result set . . . . . . .
Further reading . . . . . . . . . . . . . . . . . .
Routing . . . . . . . . . . . . . . . . . . . . .
What’s in a URL? . . . . . . . . . . . . .
React Router’s core components . . . .
Building the components of react-router
The completed app . . . . . . . . . . .
Building Route . . . . . . . . . . . . .
Building Link . . . . . . . . . . . . . .
Building Router . . . . . . . . . . . . .
Building Redirect . . . . . . . . . . .
Using react-router . . . . . . . . . .
More Route . . . . . . . . . . . . . . .
Using Switch . . . . . . . . . . . . . .
Dynamic routing with React Router . . .
The completed app . . . . . . . . . . .
The server’s API . . . . . . . . . . . .
Starting point of the app . . . . . . . .
Using URL params . . . . . . . . . . .
Propagating pathnames as props . . . .
Dynamic menu items with NavLink . .
Supporting authenticated routes . . . . .
The Client library . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

304
304
305
309
313
316
319
323
325
332
334
336
340
342
344
348
351
357
362
366
370

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

373
373
375
376
376
378
385
390
395
399
400
405
407
408
411
413
419
426
431
434
435

CONTENTS

Implementing login . . . . . . . . . . . .
PrivateRoute, a higher-order component
Redirect state . . . . . . . . . . . . . . .
Recap . . . . . . . . . . . . . . . . . . . . .
Further Reading . . . . . . . . . . . . . .

Part II

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

436
442
446
448
448

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449

Intro to Flux and Redux . . . . . . . . . . . . . .
Why Flux? . . . . . . . . . . . . . . . . . . . .
Flux is a Design Pattern . . . . . . . . . . .
Flux overview . . . . . . . . . . . . . . . . .
Flux implementations . . . . . . . . . . . . . .
Redux . . . . . . . . . . . . . . . . . . . . . . .
Redux’s key ideas . . . . . . . . . . . . . . .
Building a counter . . . . . . . . . . . . . . . .
Preparation . . . . . . . . . . . . . . . . . .
Overview . . . . . . . . . . . . . . . . . . .
The counter’s actions . . . . . . . . . . . . .
Incrementing the counter . . . . . . . . . .
Decrementing the counter . . . . . . . . . .
Supporting additional parameters on actions
Building the store . . . . . . . . . . . . . . . .
Try it out . . . . . . . . . . . . . . . . . . .
The core of Redux . . . . . . . . . . . . . . . .
Next up . . . . . . . . . . . . . . . . . . . .
The beginnings of a chat app . . . . . . . . . .
Previewing . . . . . . . . . . . . . . . . . .
State . . . . . . . . . . . . . . . . . . . . . .
Actions . . . . . . . . . . . . . . . . . . . .
Building the reducer() . . . . . . . . . . . . .
Initializing state . . . . . . . . . . . . . . .
Handling the ADD_MESSAGE action . . . . . .
Handling the DELETE_MESSAGE action . . . .
Subscribing to the store . . . . . . . . . . . . .
createStore() in full . . . . . . . . . . . .
Connecting Redux to React . . . . . . . . . . .
Using store.getState() . . . . . . . . . . .
Using store.subscribe() . . . . . . . . . .
Using store.dispatch() . . . . . . . . . . .
The app’s components . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

450
450
450
451
452
452
452
453
453
454
455
456
457
459
460
464
465
466
466
466
468
469
469
469
470
473
475
477
480
480
480
481
481

CONTENTS

Preparing App.js . . . . . . .
The App component . . . . . .
The MessageInput component
The MessageView component
Next up . . . . . . . . . . . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

482
483
484
486
488

Intermediate Redux . . . . . . . . . . . . . . . . . .
Preparation . . . . . . . . . . . . . . . . . . .
Using createStore() from the redux library . .
Try it out . . . . . . . . . . . . . . . . . . . .
Representing messages as objects in state . . . .
Updating ADD_MESSAGE . . . . . . . . . . . . .
Updating DELETE_MESSAGE . . . . . . . . . . .
Updating the React components . . . . . . . .
Introducing threads . . . . . . . . . . . . . . . .
Supporting threads in initialState . . . . .
Supporting threads in the React components .
Modifying App . . . . . . . . . . . . . . . . .
Turning MessageView into Thread . . . . . . .
Try it out . . . . . . . . . . . . . . . . . . . .
Adding the ThreadTabs component . . . . . . . .
Updating App . . . . . . . . . . . . . . . . . .
Creating ThreadTabs . . . . . . . . . . . . . .
Try it out . . . . . . . . . . . . . . . . . . . .
Supporting threads in the reducer . . . . . . . . .
Updating ADD_MESSAGE in the reducer . . . . .
Updating the MessageInput component . . . .
Try it out . . . . . . . . . . . . . . . . . . . .
Updating DELETE_MESSAGE in the reducer . . .
Try it out . . . . . . . . . . . . . . . . . . . .
Adding the action OPEN_THREAD . . . . . . . . . .
The action object . . . . . . . . . . . . . . . .
Modifying the reducer . . . . . . . . . . . . .
Dispatching from ThreadTabs . . . . . . . . .
Try it out . . . . . . . . . . . . . . . . . . . .
Breaking up the reducer function . . . . . . . . .
A new reducer() . . . . . . . . . . . . . . . .
Updating threadsReducer() . . . . . . . . . .
Try it out . . . . . . . . . . . . . . . . . . . .
Adding messagesReducer() . . . . . . . . . . . .
Modifying the ADD_MESSAGE action handler . .
Creating messagesReducer() . . . . . . . . .
Modifying the DELETE_MESSAGE action handler

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

489
489
490
491
491
492
494
495
497
498
500
501
502
503
503
504
505
505
506
506
512
513
514
516
517
517
517
518
519
520
521
523
526
527
527
528
529

CONTENTS

Adding DELETE_MESSAGE to messagesReducer() .
Defining the initial state in the reducers . . . . . . .
Initial state in reducer() . . . . . . . . . . . . . .
Adding initial state to activeThreadIdReducer()
Adding initial state to threadsReducer() . . . . .
Try it out . . . . . . . . . . . . . . . . . . . . . .
Using combineReducers() from redux . . . . . . . .
Next up . . . . . . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

532
533
534
534
535
536
536
537

Using Presentational and Container Components with Redux
Presentational and container components . . . . . . . . .
Splitting up ThreadTabs . . . . . . . . . . . . . . . . . .
Splitting up Thread . . . . . . . . . . . . . . . . . . . . .
Removing store from App . . . . . . . . . . . . . . . . . . .
Try it out . . . . . . . . . . . . . . . . . . . . . . . . . .
Generating containers with react-redux . . . . . . . . . . .
The Provider component . . . . . . . . . . . . . . . . .
Wrapping App in Provider . . . . . . . . . . . . . . . . .
Using connect() to generate ThreadTabs . . . . . . . . .
Using connect() to generate ThreadDisplay . . . . . . .
Action creators . . . . . . . . . . . . . . . . . . . . . . . . .
Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . .
Asynchronicity and server communication . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

539
539
541
546
552
553
553
554
554
555
559
564
568
568

Using GraphQL . . . . . . . . . . .
Your First GraphQL Query . . .
GraphQL Benefits . . . . . . . .
GraphQL vs. REST . . . . . . . .
GraphQL vs. SQL . . . . . . . .
Relay and GraphQL Frameworks
Chapter Preview . . . . . . . . .
Consuming GraphQL . . . . . .
Exploring With GraphiQL . . . .
GraphQL Syntax 101 . . . . . . .
Complex Types . . . . . . . . . .
Unions . . . . . . . . . . . . .
Fragments . . . . . . . . . . .
Interfaces . . . . . . . . . . .
Exploring a Graph . . . . . . . .
Graph Nodes . . . . . . . . . . .
Viewer . . . . . . . . . . . . . .
Graph Connections and Edges .
Mutations . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

570
570
572
573
574
574
576
576
576
580
584
584
585
586
587
590
591
592
596

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

CONTENTS

Subscriptions . . . . . . .
GraphQL With JavaScript
GraphQL With React . .
Wrapping Up . . . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

597
598
599
601

GraphQL Server . . . . . . . . . . . . . . . . .
Writing a GraphQL Server . . . . . . . . .
Special setup for Windows users . . . . . .
Game Plan . . . . . . . . . . . . . . . .
Express HTTP Server . . . . . . . . . . .
Adding First GraphQL Types . . . . . .
Adding GraphiQL . . . . . . . . . . . .
Introspection . . . . . . . . . . . . . . .
Mutation . . . . . . . . . . . . . . . . .
Rich Schemas and SQL . . . . . . . . . .
Setting Up The Database . . . . . . . . .
Schema Design . . . . . . . . . . . . . .
Object and Scalar Types . . . . . . . . .
Lists . . . . . . . . . . . . . . . . . . . .
Performance: Look-Ahead Optimizations
Lists Continued . . . . . . . . . . . . . .
Connections . . . . . . . . . . . . . . . . .
Authentication . . . . . . . . . . . . . .
Authorization . . . . . . . . . . . . . . .
Rich Mutations . . . . . . . . . . . . . .
Relay and GraphQL . . . . . . . . . . .
Performance: N+1 Queries . . . . . . . .
Summary . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

602
602
602
603
603
606
608
610
611
614
615
619
621
626
628
631
634
641
643
647
650
651
655

Relay . . . . . . . . . . . . . . . . . . . . . . . .
Introduction . . . . . . . . . . . . . . . . . .
What We’re Going to Cover . . . . . . . .
What We’re Building . . . . . . . . . . . .
Guide to the Code Structure . . . . . . . .
Relay is a Data Architecture . . . . . . . . . .
Relay GraphQL Conventions . . . . . . . . .
Exploring Relay Conventions in GraphQL
Fetching Objects By ID . . . . . . . . . . .
Walking Connections . . . . . . . . . . . .
Changing Data with Mutations . . . . . .
Relay GraphQL Queries Summary . . . . .
Adding Relay to Our App . . . . . . . . . . .
Quick Look at the Goal . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

657
657
658
658
662
663
664
665
665
669
674
675
675
675

CONTENTS

A Preview of the Author Page . . . . . . . . .
Containers, Queries, and Fragments . . . . . .
Validating Our Relay Queries at Compile Time
Setting Up Routing . . . . . . . . . . . . . . .
Adding Relay to Our Routes . . . . . . . . . .
App Component . . . . . . . . . . . . . . . . .
AuthorQueries Component . . . . . . . . . .
AuthorPage Component . . . . . . . . . . . .
Try It Out . . . . . . . . . . . . . . . . . . . .
AuthorPage with Styles . . . . . . . . . . . . .
BooksPage . . . . . . . . . . . . . . . . . . . . .
BooksPage Route . . . . . . . . . . . . . . . .
BooksPage Component . . . . . . . . . . . . .
BooksPage render() . . . . . . . . . . . . . .
BookItem . . . . . . . . . . . . . . . . . . . .
BookItem Fragment . . . . . . . . . . . . . .
Fragment Value Masking . . . . . . . . . . . .
Improving the AuthorPage . . . . . . . . . . .
Changing Data With Mutations . . . . . . . . . .
Building a Book’s Page . . . . . . . . . . . . . .
Book Page Editing . . . . . . . . . . . . . . .
Mutations . . . . . . . . . . . . . . . . . . . . .
Defining a Mutation Object . . . . . . . . . .
Inline Editing . . . . . . . . . . . . . . . . . .
Conclusion . . . . . . . . . . . . . . . . . . . . .
Where to Go From Here . . . . . . . . . . . . . .
React Native . . . . . .
Init . . . . . . . . .
Routing . . . . . . .
 . . .
renderScene() .

.
.
.
.
.

. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
configureScene() . . . . . . . . . . . . . . .
Web components vs. Native components . . . . .
 . . . . . . . . . . . . . . . . . . . .
 . . . . . . . . . . . . . . . . . . . .
 . . . . . . . . . . . . . . . . . . . .
 . . . . . . . . . . . . . . . . .
,  . . . . . . . . . . . . . . . . . . . .
 . . . . . . . . . . . .
 . . . . . . . . . . . . . . . . . .
 . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

678
679
679
685
687
688
689
689
691
693
695
695
696
698
699
701
701
703
706
707
710
713
714
718
720
721

. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
/>, and  . . . . . . .
Styles . . . . . . . . . . . . .
StyleSheet . . . . . . . . .
Flexbox . . . . . . . . . .
HTTP requests . . . . . . . .
What is a promise . . . . . .
Enter Promises . . . . . .
Single-use guarantee . . . . .
Creating a promise . . . . . .
Debugging with React Native
Where to go from here . . . .

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

737
745
746
747
765
766
768
770
770
772
773

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

775
776
777
777
778
779
780
780
781
782
783
784
785
786
787
787
788

Appendix B: ES6 . . . . . . . . . . .
Prefer const and let over var
Arrow functions . . . . . . .
Modules . . . . . . . . . . . .
Object.assign() . . . . . . .
Template literals . . . . . . .
The spread operator (...) . .
Enhanced object literals . . .
Default arguments . . . . . .
Destructuring assignments . .

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

790
790
790
793
796
797
797
798
798
799

Appendix A: PropTypes . . . .
Validators . . . . . . . . .
string . . . . . . . . . . . .
number . . . . . . . . . . .
boolean . . . . . . . . . . .
function . . . . . . . . . .
object . . . . . . . . . . . .
object shape . . . . . . . .
multiple types . . . . . . .
instanceOf . . . . . . . . .
array . . . . . . . . . . . .
array of type . . . . . . . .
node . . . . . . . . . . . .
element . . . . . . . . . . .
any type . . . . . . . . . .
Optional & required props .
custom validator . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

Changelog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 802
Revision 32 - 2017-06-14 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 802

CONTENTS

Revision 31 - 2017-05-18 .
Revision 30 - 2017-04-20 .
Revision 29 - 2017-04-13 .
Revision 28 - 2017-04-10 .
Revision 27 - 2017-03-16 .
Revision 26 - 2017-02-22 .
Revision 25 - 2017-02-17 .
Revision 24 - 2017-02-08 .
Revision 23 - 2017-02-06 .
Revision 22 - 2017-02-01 .
Revision 21 - 2017-01-27 .
Revision 20 - 2017-01-10 .
Revision 19 - 2016-12-20 .
Revision 18 - 2016-11-22 .
Revision 17 - 2016-11-04 .
Revision 16 - 2016-10-12 .
Revision 15 - 2016-10-05 .
Revision 14 - 2016-08-26 .
Revision 13 - 2016-08-02 .
Revision 12 - 2016-07-26 .
Revision 11 - 2016-07-08 .
Revision 10 - 2016-06-24 .
Revision 9 - 2016-06-21 .
Revision 8 - 2016-06-02 .
Revision 7 - 2016-05-13 .
Revision 6 - 2016-05-13 .
Revision 5 - 2016-04-25 .
Revision 4 - 2016-04-22 .
Revision 3 - 2016-04-08 .
Revision 2 - 2016-03-16 .
Revision 1 - 2016-02-14 .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

802
802
802
802
802
803
803
803
803
803
803
804
804
804
804
804
804
804
804
804
805
805
805
805
805
805
805
805
805
806
806

CONTENTS

1

Book Revision
Revision 32 - Supports React 15.5.4 (2017-06-14)

Bug Reports
If you’d like to report any bugs, typos, or suggestions just email us at: react@fullstack.io1 .

Chat With The Community!
There’s an unofficial community chat room for this book using Gitter. If you’d like to hang out with
other people learning React, come join us on Gitter2 !

Be notified of updates via Twitter
If you’d like to be notified of updates to the book on Twitter, follow @fullstackio3

We’d love to hear from you!
Did you like the book? Did you find it helpful? We’d love to add your face to our list of testimonials
on the website! Email us at: react@fullstack.io4 .
1

mailto:react@fullstack.io?Subject=Fullstack%20React%20book%20feedback
https://gitter.im/fullstackreact/fullstackreact
3
https://twitter.com/fullstackio
4
mailto:react@fullstack.io?Subject=react%202%20testimonial
2

Foreword
Web development is often seen as a crazy world where the way you develop software is by throwing
hacks on top of hacks. I believe that React breaks from this pattern and instead has been designed
from first principle which gives you a solid foundation to build on.
A major source of bugs for front-end applications was
around synchronizing the data model with the DOM. It
is very hard to make sure that whenever data changes,
everything in the UI is updated with it.
React’s first innovation was to introduce a pureJavaScript representation of the DOM and implement
diffing in userland and then use events which send
simple commands: create, update, delete.
With React, by conceptually re-rendering everything
whenever anything changes, not only do you have
code that is safe by default, it is also less work as you
only need to write the creation path: updates are taken
care of for you.
Christopher Chedeau - Front-end Engineer
Browsers have, for a long time, been incompatible in
at Facebook
various ways due to the large API surface area of what
they have to support to make the DOM work. Not only
does React provide a great way to solve browser differences, but it enables use cases that were never
before possible for a front-end library, such as server-side rendering and the ability to implement
rendering targets like native iOS, Android, and even hardware components.

But the most important thing about React and the main reason why you should read this book: not
only will you use it to make great applications for your users, it will also make you a better
developer. Libraries come and go all the time and React is likely going to be no exception. What
makes it special is that it teaches you concepts that can be reused throughout your entire career.
You will become better at JavaScript because React doesn’t come with a templating system.
Instead, React pushes you to use the full power of JavaScript to build your user interface.
You are going to practice using parts of functional programming with map and filter and also
encouraged to use the latest features of JavaScript (including ES6). By not abstracting away data
management, React will force you to think about how to architect your app and encourage you to
consider concepts like immutability.
I’m very proud that the community built around React is not afraid of “rethinking best practices.”
The community challenges the status quo in many areas. My advice to you is to read this excellent

Foreword

3

book to learn and understand the fundamentals of React. Learning new concepts may feel strange
but “give it 5 minutes” and practice them until you feel comfortable.
Then, try to break the rules. There is no one best way to build software and React is no exception.
React actually embraces this fact by providing you with escape hatches when you want to do things
outside of the React-way.
Come up with crazy ideas and who knows, maybe you are going to invent the successor to React!
– Christopher Chedeau @vjeux5 Front-end Engineer at Facebook

5

https://twitter.com/Vjeux

How to Get the Most Out of This Book
Overview
This book aims to be the single most useful resource on learning React. By the time you’re done
reading this book, you (and your team) will have everything you need to build reliable, powerful
React apps.
React core is lean and powerful. After the first few chapters, you’ll have a solid understanding of
React’s fundamentals and will be able to build a wide array of rich, interactive web apps with the
framework.
But beyond React’s core, there are many tools in its ecosystem that you might find helpful for
building production apps. Things like client-side routing between pages, managing complex state,
and heavy API interaction at scale.
This book consists of two parts.
In Part I, we cover all the fundamentals with a progressive, example-driven approach. You’ll create
your first apps, learn how to write components, start handling user interaction, manage rich
forms, and even interact with servers.
We bookend the first part by exploring the inner workings of Create React App (Facebook’s tool
for running React apps), writing automated unit tests, and building a multi-page app that uses
client-side routing.
Part II of this book moves into more advanced concepts that you’ll see used in large, production
applications. These concepts explore strategies for data architecture, transport, and management:
Redux is a state management paradigm based on Facebook’s Flux architecture. Redux provides a
structure for large state trees and allows you to decouple user interaction in your app from state
changes.
GraphQL is a powerful, typed, REST API alternative where the client describes the data it needs.
We also cover how to write your own GraphQL servers for your own data.
Relay is the glue between GraphQL and React. Relay is a data-fetching library that makes it easy to
write flexible, performant apps without a lot of data-fetching code.
Finally, in the last chapter, we’ll talk about how to write native, cross-platform mobile apps using
React Native.
There are a few guidelines we want to give you in order to get the most out of this book.
First, know that you do not need to read this book linearly from cover-to-cover. However, we’ve
ordered the contents of the book in a way we feel fits the order you should learn the concepts. We

How to Get the Most Out of This Book

2

encourage you to learn all the concepts in Part I of the book first before diving into concepts in Part
II.
Second, keep in mind this package is more than just a book - it’s a course complete with example
code for every chapter. Below, we’ll tell you:
• how to approach the code examples and
• how to get help if something goes wrong

Running Code Examples
This book comes with a library of runnable code examples. The code is available to download from
the same place where you purchased this book. If you purchased this book on Amazon, you should
have received an email with instructions.
If you have any trouble finding or downloading the code examples, email us at react@fullstack.io.
We use the program npm6 to run every example in this book. You can boot most apps with the
following two commands:
npm install
npm start

If you’re unfamiliar with npm, we cover how to get it installed in the Setting Up section in
the first chapter.

After running npm start, you will see some output on your screen that will tell you what URL to
open to view your app.
Some apps require a few more commands to setup. If you’re ever unclear on how to run a
particular sample app, checkout the README.md in that project’s directory. Every sample project
contains a README.md that will give you the instructions you need to run each app.

Project setups
The first two projects begin with a simple React setup that allows us to quickly write React
applications.
From there, with a couple exceptions, every project in this book was built using Create React App7 .
Create React App is based on Webpack, a tool which helps process and bundle our various JavaScript,
CSS, HTML, and image files. We explore Create React App in-depth in the chapter “Using Webpack
with Create React App.” But, Create React App is not a requirement for using React. It’s simply a
wrapper around Webpack (and some other tooling) that makes it easy to get started.
6
7

https://www.npmjs.com/
https://github.com/facebookincubator/create-react-app

How to Get the Most Out of This Book

3

Code Blocks and Context
Nearly every code block in this book is pulled from a runnable code example which you can find
in the sample code. For example, here is a code block pulled from the first chapter:
voting_app/public/js/app-2.js

class ProductList extends React.Component {
render() {
return (
); } } Notice that the header of this code block states the path to the file which contains this code: voting_app/public/js/app-2.js. If you ever feel like you’re missing the context for a code example, open up the full code file using your favorite text editor. This book is written with the expectation that you’ll also be looking at the example code alongside the manuscript. For example, we often need to import libraries to get our code to run. In the early chapters of the book we show these import statements, because it’s not clear where the libraries are coming from otherwise. However, the later chapters of the book are more advanced and they focus on key concepts instead of repeating boilerplate code that was covered earlier in the book. If at any point you’re not clear on the context, open up the code example on disk. Code Block Numbering In this book, we sometimes build up a larger example in steps. If you see a file being loaded that has a numeric suffix, that generally means we’re building up to something bigger. For instance, above the code block has the filename: app-2.js. When you see the -N.js syntax that means we’re building up to a final version of the file. You can jump into that file and see the state of all the code at that particular stage. Getting Help While we’ve made every effort to be clear, precise, and accurate you may find that when you’re writing your code you run into a problem. Generally, there are three types of problems: How to Get the Most Out of This Book 4 • A “bug” in the book (e.g. how we describe something is wrong) • A “bug” in our code • A “bug” in your code If you find an inaccuracy in how we describe something, or you feel a concept isn’t clear, email us! We want to make sure that the book is both accurate and clear. Similarly, if you’ve found a bug in our code we definitely want to hear about it. If you’re having trouble getting your own app working (and it isn’t our example code), this case is a bit harder for us to handle. Your first line of defense, when getting help with your custom app, should be our unofficial community chat room8 . We (the authors) are there from time-to-time, but there are hundreds of other readers there who may be able to help you faster than we can. If you’re still stuck, we’d still love to hear from you, and here some tips for getting a clear, timely response. Emailing Us If you’re emailing us asking for technical help, here’s what we’d like to know: • • • • • • • What revision of the book are you referring to? What operating system are you on? (e.g. Mac OS X 10.8, Windows 95) Which chapter and which example project are you on? What were you trying to accomplish? What have you tried9 already? What output did you expect? What actually happened? (Including relevant log output.) The absolute best way to get technical support is to send us a short, self-contained example of the problem. Our preferred way to receive this would be for you to send us a Plunkr link by using this URL10 . That URL contains a runnable, boilerplate React app. If you can copy and paste your code into that project, reproduce your error, and send it to us you’ll greatly increase the likelihood of a prompt, helpful response. When you’ve written down these things, email us at react@fullstack.io. We look forward to hearing from you. 8 https://gitter.im/fullstackreact/fullstackreact http://mattgemmell.com/what-have-you-tried/ 10 https://plnkr.co/edit/tpl:a3vkhunC1Na5BG6GY2Gf 9 How to Get the Most Out of This Book 5 Technical Support Response Time We perform our free, technical support once per week. If you need a faster response time, and help getting any of your team’s questions answered, then you may consider our premium support option11 . Get excited Writing web apps with React is fun. And by using this book, you’re going to learn how to build real React apps fast. (And much faster than spending hours parsing out-dated blog posts.) If you’ve written client-side JavaScript before, you’ll find React refreshingly intuitive. If this is your first serious foray into the front-end, you’ll be blown away at how quickly you can create something worth sharing. So hold on tight - you’re about to become a React expert and have a lot of fun along the way. Let’s dig in! • Nate (@eigenjoy12 ) & Anthony 11 mailto:react@fullstack.io?Subject=React%20Premium%20Support&Body=Hello%21%20I%27m%20interested%20in%20premium%20React% 20support%20for%20our%20team 12 https://twitter.com/eigenjoy Part I Your first React Web Application Building Product Hunt In this chapter, you’re going to get a crash course on React by building a simple voting application inspired by Product Hunt13 . You’ll become familiar with how React approaches front-end development and all the fundamentals necessary to build an interactive React app from start to finish. Thanks to React’s core simplicity, by the end of the chapter you’ll already be well on your way to writing a variety of fast, dynamic interfaces. We’ll focus on getting our React app up and running fast. We take a deeper look at concepts covered in this section throughout the book. Setting up your development environment Code editor As you’ll be writing code throughout this book, you’ll need to make sure you have a code editor you’re comfortable working with. If you don’t already have a preferred editor, we recommend installing Atom14 or Sublime Text15 . Node.js and npm For all the projects in this book, we’ll need to make sure we have a working Node.js16 development environment along with npm. There are a couple different ways you can install Node.js so please refer to the Node.js website for detailed information: https://nodejs.org/download/17 If you’re on a Mac, your best bet is to install Node.js directly from the Node.js website instead of through another package manager (like Homebrew). Installing Node.js via Homebrew is known to cause some issues. The Node Package Manager (npm for short) is installed as a part of Node.js. To check if npm is available as a part of our development environment, we can open a terminal window and type: 13 http://producthunt.com http://atom.io 15 https://www.sublimetext.com/ 16 http://nodejs.org 17 https://nodejs.org/download/ 14 Your first React Web Application 8 $ npm -v If a version number is not printed out and you receive an error, make sure to download a Node.js installer that includes npm. Install Git The app in this chapter requires Git to install some third-party libraries. If you don’t have Git installed, see these instructions18 for installing Git for your platform. After installing Git, we recommend restarting your computer. Browser Last, we highly recommend using the Google Chrome Web Browser19 to develop React apps. We’ll use the Chrome developer toolkit throughout this book. To follow along with our development and debugging we recommend downloading it now. Special instruction for Windows users All the code in this book has been tested on Windows 10 with PowerShell. Ensure IIS is installed If you’re on a Windows machine and have yet to do any web development on it, you may need to install IIS (Internet Information Services) in order to run web servers locally. See this tutorial20 for installing IIS. JavaScript ES6/ES7 JavaScript is the language of the web. It runs on many different browsers, like Google Chrome, Firefox, Safari, Microsoft Edge, and Internet Explorer. Different browsers have different JavaScript interpreters which execute JavaScript code. Its widespread adoption as the internet’s client-side scripting language led to the formation of a standards body which manages its specification. The specification is called ECMAScript or ES. 18 https://git-scm.com/book/en/v2/Getting-Started-Installing-Git https://www.google.com/chrome/ 20 http://www.howtogeek.com/112455/how-to-install-iis-8-on-windows-8/ 19 Your first React Web Application 9 The 5th edition of the specification is called ES5. You can think of ES5 as a “version” of the JavaScript programming language. Finalized in 2009, ES5 was adopted by all major browsers within a few years. The 6th edition of JavaScript is referred to as ES6. Finalized in 2015, the latest versions of major browsers are still finishing adding support for ES6 as of 2017. ES6 is a significant update. It contains a whole host of new features for JavaScript, almost two dozen in total. JavaScript written in ES6 is tangibly different than JavaScript written in ES5. ES7, a much smaller update that builds on ES6, was ratified in June 2016. ES7 contains only two new features. As the future of JavaScript, we want to write our code in ES6/ES7 today. But we also want our JavaScript to run on older browsers until they fade out of widespread use. We see later in this chapter how we can enjoy the benefits of ES6/ES7 today while still supporting the vast majority of the world’s browsers. This book is written with JavaScript ES7. Because ES6 ratified a majority of these new features, we’ll commonly refer to these new features as ES6 features. We’ve included an appendix on the ES6 syntax that we use, “Appendix B: ES6.” We’ll often refer to the appendix when encountering ES6 syntax for the first time, but if ever syntax seems unfamiliar to you it’s worth checking Appendix B to see if it’s new ES6 JavaScript syntax. ES6 is sometimes referred to as ES2015, the year of its finalization. ES7, in turn, is often referred to as ES2016. Getting started Sample Code All the code examples you find in each chapter are available in the code package that came with the book. In that code package you’ll find completed versions of each app as well as boilerplates that we will use to build those apps together. Each chapter provides detailed instruction on how to follow along on your own. While coding along with the book is not necessary, we highly recommend doing so. Playing around with examples and sample code will help solidify and strengthen concepts. Previewing the application We’ll be building a basic React app that will allow us to touch on React’s most important concepts at a high-level before diving into them in subsequent sections. Let’s begin by taking a look at a working implementation of the app. Open up the sample code folder that came with the book. Change to the voting_app/ directory in the terminal: 10 Your first React Web Application $ cd voting_app/ If you’re not familiar with cd, it stands for “change directory.” If you’re on a Mac, do the following to open terminal and change to the proper directory: 1. 2. 3. 4. 5. Open up /Applications/Utilities/Terminal.app. Type cd, without hitting enter. Tap the spacebar. In the Finder, drag the voting_app/ folder on to your terminal window. Hit Enter. Your terminal is now in the proper directory. Throughout the book, a code block starting with a $ signifies a command to be run in your terminal. First, we’ll need to use npm to install all our dependencies: $ npm install With our dependencies installed, we can boot the server using the npm start command $ npm start The boot process will print some text to the console: Boot process output In addition, your browser might automatically launch and open the app. If it doesn’t, you can view the running application at the URL http://localhost:3000: 11 Your first React Web Application Completed version of the app This demo app is a site like Product Hunt21 or Reddit22 . These sites have lists of links that users can vote on. Like those sites, in our app we can up-vote products. All products are sorted instantaneously by number of votes. The keyboard command to quit a running Node server is CTRL+C. Prepare the app In the terminal, run ls to see the project’s layout: 21 22 http://producthunt.com http://reddit.com Your first React Web Application 12 $ ls README.md disable-browser-cache.js nightwatch.json node_modules/ package.json public/ semantic.json tests/ If you’re running on macOS or Linux, you can run ls -1p to format your output as we do above. Node apps contain a package.json which specifies the dependencies of the project. When we ran npm install, npm used our package.json to determine which dependencies to download and install. It installed them to the folder node_modules/. We explore the format of package.json in later chapters. The code we’ll be working with is inside the folder public/. Look inside that folder: $ ls public favicon.ico images/ index.html js/ semantic/ style.css vendor/ The general layout here is a common one for web apps. Inside public/ is index.html, the file that we serve to browsers that request our website. As we’ll see shortly, index.html is the centerpiece of our app. It loads in the rest of our app’s assets. Let’s look inside public/js next: Your first React Web Application 13 $ ls public/js app-1.js app-2.js app-3.js app-4.js app-5.js app-6.js app-7.js app-8.js app-9.js app-complete.js app.js seed.js Inside public/js is where we’ll put our app’s JavaScript. We’ll be writing our React app inside app.js. app-complete.js is the completed version of the app that we’re working towards, which we viewed a moment ago. In addition, we’ve included each version of app.js as we build it up throughout this chapter (app1.js, app-2.js, etc). Each code block in this chapter will reference which app version you can find it in. You can copy and paste longer code insertions from these app versions into your app.js. All projects include a handy README.md that have instructions on how to run them. To get started, we’ll ensure app-complete.js is no longer loaded in index.html. We’ll then have a blank canvas to begin work inside app.js. Open up public/index.html in your text editor. It should look like this: voting_app/public/index.html Project One Your first React Web Application 14

Popular Products

We’ll go over all the dependencies being loaded under the tag later. The heart of the HTML document is these few lines here: voting_app/public/index.html

Popular Products

For this project, we’re using Semantic UI23 for styling. Semantic UI is a CSS framework, much like Twitter’s Bootstrap24 . It provides us with a grid system and some simple styling. You don’t need to know Semantic UI in order to use this book. We’ll provide all the styling code that you need. At some point, you might want to check out the docs Semantic UI docs25 to get familiar with the framework and explore how you can use it in your own projects. The class attributes here are just concerned with style and are safe to ignore. Stripping those away, our core markup is succinct: 23 http://semantic-ui.com/ http://getbootstrap.com/ 25 http://semantic-ui.com/introduction/getting-started.html 24 Your first React Web Application 15

Popular Products

We have a title for the page (h1) and a div with an id of content. This div is where we will ultimately mount our React app. We’ll see shortly what that means. The next few lines tell the browser what JavaScript to load. To start building our own application, let’s remove the ./app-complete.js script tag completely: After we save our updated index.html and reload the web browser, we’ll see that our app has disappeared. What’s a component? Building a React app is all about components. An individual React component can be thought of as a UI component in an app. We can break apart the interface of our app into two classes of components: 16 Your first React Web Application The app’s components We have a hierarchy of one parent component and many child components. We’ll call these ProductList and Product, respectively: 1. ProductList: Contains a list of product components 2. Product: Displays a given product Not only do React components map cleanly to UI components, but they are self-contained. The markup, view logic, and often component-specific style is all housed in one place. This feature makes React components reusable. Furthermore, as we’ll see in this chapter and throughout this book, React’s paradigm for component data flow and interactivity is rigidly defined. In React, when the inputs for a component change, the framework simply re-renders that component. This gives us a robust UI consistency guarantee: With a given set of inputs, the output (how the component looks on the page) will always be the same. Our first component Let’s start off by building the ProductList component. We’ll write all our React code for the rest of this chapter inside the file public/js/app.js. Let’s open app.js and insert the component: Your first React Web Application 17 voting_app/public/js/app-1.js class ProductList extends React.Component { render() { return (
Hello, friend! I am a basic React component.
); } } React components are ES6 classes that extend the class React.Component. We’re referencing the React variable. index.html loads the React library for us so we’re able to reference it here: voting_app/public/index.html Our ProductList class has a single method, render(). render() is the only required method for a React component. React uses the return value from this method to determine what to render to the page. While JavaScript is not a classical language, ES6 introduced a class declaration syntax. ES6 classes are syntactical sugar over JavaScript’s prototype-based inheritance model. We cover the important details you need to know about classes with respect to building React components. If you’d like to learn more about ES6 classes, refer to the docs on MDN26 . There are two ways to declare React components: (1) As ES6 classes (as above) (2) Using the React.createClass() method An example of using an ES6 class: class HelloWorld extends React.Component { render() { return(

Hello, world!

) } } The same component written using the createClass function from the React library: 26 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes Your first React Web Application 18 const HelloWorld = React.createClass({ render() { return(

Hello, world!

) } }) At the time of writing, both types of declarations are in widespread use. The differences between them are minimal. We expose you to both declarations in this book. If you have some familiarity with JavaScript, the return value may be surprising: voting_app/public/js/app-1.js return (
Hello, friend! I am a basic React component.
); The syntax of the return value doesn’t look like traditional JavaScript. We’re using JSX (JavaScript eXtension syntax), a syntax extension for JavaScript written by Facebook. Using JSX enables us to write the markup for our component views in a familiar, HTML-like syntax. In the end, this JSX code compiles to vanilla JavaScript. Although using JSX is not a necessity, we’ll use it in this book as it pairs really well with React. If you don’t have much familiarity with JavaScript, we recommend you follow along and use JSX in your React code too. You’ll learn the boundaries between JSX and JavaScript with experience. JSX React components ultimately render HTML which is displayed in the browser. As such, the render() method of a component needs to describe how the view should be represented as HTML. React builds our apps with a fake representation of the Document Object Model (DOM). React calls this the virtual DOM. Without getting deep into details for now, React allows us to describe a component’s HTML representation in JavaScript. The Document Object Model (DOM) refers to the browser’s HTML tree that makes up a web page. JSX was created to make this JavaScript representation of HTML more HTML-like. To understand the difference between HTML and JSX, consider this JavaScript syntax: Your first React Web Application 19 React.createElement('div', {className: 'ui items'}, 'Hello, friend! I am a basic React component.' ) Which can be represented in JSX as:
Hello, friend! I am a basic React component.
The code readability is slightly improved in the latter example. This is exacerbated in a nested tree structure: React.createElement('div', {className: 'ui items'}, React.createElement('p', null, 'Hello, friend! I am a basic React component.') ) In JSX:

Hello, friend! I am a basic React component.

JSX presents a light abstraction over the JavaScript version, yet the legibility benefits are huge. Readability boosts our app’s longevity and makes it easier to onboard new developers. Even though the JSX above looks exactly like HTML, it’s important to remember that JSX is actually just compiled into JavaScript (ex: React.createElement('div')). During runtime React takes care of rendering the actual HTML in the browser for each component. The developer console Our first component is written and we now know that it uses a special flavor of JavaScript called JSX for improved readability. After editing and saving our app.js, let’s refresh the page in our web browser and see what changed: Your first React Web Application 20 Nothing? Every major browser comes with a toolkit that helps developers working on JavaScript code. A central part of this toolkit is a console. Think of the console as JavaScript’s primary communication medium back to the developer. If JavaScript encounters any errors in its execution, it will alert you in this developer console. Our web server, live-server, should refresh the page automatically when it detects that app.js has changed. To open the console in Chrome, navigate to View > Developer > JavaScript Console. Or, just press Command + Option + J on a Mac or Control + Shift + L on Windows/Linux. Opening the console, we are given a cryptic clue: Uncaught SyntaxError: Unexpected token < 21 Your first React Web Application Error in the console This SyntaxError prevented our code from running. A SyntaxError is thrown when the JavaScript engine encounters tokens or token order that doesn’t conform to the syntax of the language when parsing code. This error type indicates some code is out of place or mistyped. The issue? Our browser’s JavaScript parser tripped when it encountered the JSX. The parser doesn’t know anything about JSX. As far as it is concerned, this < is completely out of place. As we discussed, JSX is an extension to standard JavaScript. Let’s have our browser’s JavaScript interpreter use this extension. Babel We mentioned at the beginning of the chapter that all the code in the book would be using ES6 JavaScript. However, most browsers in use today do not fully support ES6. Babel is a JavaScript transpiler. Babel turns ES6 code into ES5 code. We call this process transpiling. So we can enjoy the features of ES6 today yet ensure our code still runs in browsers that only support ES5. Another handy feature of Babel is that it understands JSX. Babel compiles our JSX into vanilla ES5 JS that our browser can then interpret and execute. We just need to instruct the browser that we want to use Babel to compile and run our JavaScript code. The sample code’s index.html already imports Babel in the head tags of index.html: Your first React Web Application 22 All we need to do is tell our JavaScript runtime that our code should be compiled by Babel. We can do this by setting the type attribute when we import the script in index.html to text/babel. Open index.html and change the script tag that loads ./js/app.js. We’re going to add two attributes: The attribute type="text/babel" indicates to Babel that we would like it to handle the loading of this script. The attribute data-plugins specifies a special Babel plugin we use in this book. We discuss this plugin at the end of the chapter. Save index.html and reload the page. Still nothing. However, the console no longer has the error. Depending on your version of Chrome, you might see some warnings (highlighted in yellow as opposed to red). These warnings are safe to ignore. Babel successfully compiled our JSX into JavaScript and our browser was able to run that JavaScript without any issues. Your first React Web Application 23 So what’s happening? We’ve defined the component, but we haven’t told React to do anything with it yet. We need to tell the React framework that our component should be inserted on this page. Depending on your version of Chrome, you might see two errors. The first: Fetching scripts with an invalid type/language attributes is deprecated and will\ be removed in M56, around January 2017. This warning is misleading and safe to ignore. The second: You are using the in-browser Babel transformer. Be sure to precompile your scrip\ ts for production Again, safe to ignore. To get up and running quickly, we’re having Babel transpile on-thefly in the browser. We explore other JavaScript transpiling strategies later in the book that are more suitable for production. ReactDOM.render() We need to instruct React to render this ProductList inside a specific DOM node. Add the following code below the component inside app.js: voting_app/public/js/app-1.js class ProductList extends React.Component { render() { return (
Hello, friend! I am a basic React component.
); } } ReactDOM.render( , document.getElementById('content') ); 24 Your first React Web Application ReactDOM is from the react-dom library that we also include in index.html. We pass in two arguments to the ReactDOM.render() method. The first argument is what we’d like to render. The second argument is where to render it: ReactDOM.render([what], [where]); Here, for the “what,” we’re passing in a reference to our React component ProductList in JSX. For the “where,” you might recall index.html contains a div tag with an id of content: voting_app/public/index.html
We pass in a reference to that DOM node as the second argument to ReactDOM.render(). At this point, it’s interesting to note that we use different casing between the different types of React element declarations. We have HTML DOM elements like
and a React component called . In React, native HTML elements always start with a lowercase letter whereas React component names always start with an uppercase letter. With ReactDOM.render() now at the end of app.js, save the file and refresh the page in the browser: Our component is rendered to the page To recap, we wrote a React component using an ES6 class as well as JSX. We specified that we wanted Babel to transpile this code to ES5. We then used ReactDOM.render() to write this component to the DOM. Your first React Web Application 25 While an accomplishment, our current ProductList component is rather uninteresting. We eventually want ProductList to render a list of products. Each product will be its own UI element, a fragment of HTML. We can represent each of these elements as their own component, Product. Central to its paradigm, React components can render other React components. We’ll have ProductList render Product components, one for each product we’d like to show on the page. Each of these Product components will be a child component to ProductList, the parent component. Building Product Let’s build our child component, Product, that will contain a product listing. Just like with the ProductList component, we’ll declare a new ES6 class that extends React.Component. We’ll define a single method, render(): class Product extends React.Component { render() { return (
{/* ... todo ... */}
); } } ReactDOM.render( // ... ); For every product, we’ll add an image, a title, a description, and an avatar of the post author. The markup is below: voting_app/public/js/app-2.js class Product extends React.Component { render() { return (
Your first React Web Application 26
Fort Knight

Authentic renaissance actors, delivered in just two weeks.

Submitted by:
); } } ReactDOM.render( The title of the code block above references the location of this example in the book’s code download (voting_app/public/js/app-2.js). This pattern will be common throughout the book. If you want to copy and paste the markup into your app.js, refer to this file. Again, we’ve used a bit of SemanticUI styling in our code here. As we discussed previously, this JSX code will be transpiled to regular JavaScript in the browser. Because it runs in the browser as JavaScript, we cannot use any reserved JavaScript words in JSX. class is a reserved word. Therefore, React has us use the attribute name className. Later, when the HTML element reaches the page, this attribute name will be written as class. Structurally, the Product component is similar to the ProductList component. Both have a single render() method which returns information about an eventual HTML structure to display. Remember, the JSX components return is not actually the HTML that gets rendered, but is the representation that we want React to render in the DOM. To use the Product component, we can modify the render output of our parent ProductList component to include the child Product component: Your first React Web Application 27 voting_app/public/js/app-2.js class ProductList extends React.Component { render() { return (
); } } Save app.js and refresh the web browser. With this update, we now have two React components being rendered in our app. The ProductList parent component is rendering the Product component as a child nested underneath its root div element. While neat, at the moment the child Product component is static. We hard-coded an image, the name, the description, and author details. To use this component in a meaningful way, we’ll want to change it to be data-driven and therefore dynamic. Making Product data-driven Driving the Product component with data will allow us to dynamically render the component based upon the data that we give it. Let’s familiarize ourselves with the product data model. Your first React Web Application 28 The data model In the sample code, we’ve included a file inside public/js called seed.js. seed.js contains some example data for our products (it will “seed” our app’s data). The seed.js file contains a JavaScript object called Seed.products. Seed.products is an array of JavaScript objects, each representing a product object: voting_app/public/js/seed.js const products = [ { id: 1, title: 'Yellow Pail', description: 'On-demand sand castle construction expertise.', url: '#', votes: generateVoteCount(), submitterAvatarUrl: 'images/avatars/daniel.jpg', productImageUrl: 'images/products/image-aqua.png', }, Each product has a unique id and a handful of properties including a title and description. votes are randomly generated for each one with the included function generateVoteCount(). We can use the same attribute keys in our React code. Using props We want to modify our Product component so that it no longer uses static, hard-coded attributes. Instead, we want it to be able to accept data passed down from its parent, ProductList. Setting up our component structure in this way enables our ProductList component to dynamically render any number of Product components that each have their own unique attributes. Data flow will look like this: Your first React Web Application 29 The way data flows from parent to child in React is through props. When a parent renders a child, it can send along props the child depends on. Let’s see this in action. First, let’s modify ProductList to pass down props to Product. seed.js will save us from having to create a bunch of data manually. Let’s pluck the first object off of the Seed.products array and use that as data for a single product: voting_app/public/js/app-3.js class ProductList extends React.Component { render() { const product = Seed.products[0]; return (
); } } Here, the product variable is set to a JavaScript object that describes the first of our products. We pass the product’s attributes along individually to the Product component using the syntax [propName]=[propValue]. The syntax of assigning attributes in JSX is exactly the same as HTML and XML. There are two interesting things here. The first is the braces ({}) around each of the property values: voting_app/public/js/app-3.js id={product.id} In JSX, braces are a delimiter, signaling to JSX that what resides in-between the braces is a JavaScript expression. The other delimiter is using quotes for strings, like this: Your first React Web Application 30 id='1' JSX attribute values must be delimited by either braces or quotes. If type is important and we want to pass in something like a Number or a null, use braces. If you’ve programmed with ES5 JavaScript before, you might be used to using var as opposed to const or let. See Appendix B for more on these new declarations. Now the ProductList component is passing props down to Product. Our Product component isn’t using them yet, so let’s modify the component to use these props. In React, a component can access all its props through the object this.props. Inside of Product, the this.props object will look like this: { "id": 1, "title": "Yellow Pail", "description": "On-demand sand castle construction expertise.", "url": "#", "votes": 41, "submitterAvatarURL": "images/avatars/daniel.jpg", "productImageUrl": "images/products/image-aqua.png" } Let’s swap out everywhere that we hard-coded data and use props instead. While we’re here, we’ll add a bit more markup like the description and the up-vote icon: voting_app/public/js/app-3.js class Product extends React.Component { render() { return (
{this.props.title}

{this.props.description}

Submitted by:
); } } Again, everywhere inside of our JSX where we’re interpolating a variable we delimit the variable with braces ({}). Note that we’re inserting data both as text content inside of tags like this: voting_app/public/js/app-3.js
{this.props.votes}
As well as for attributes on HTML elements: voting_app/public/js/app-3.js Your first React Web Application 32 Interweaving props with HTML elements in this way is how we create dynamic, data-driven React components. this is a special keyword in JavaScript. The details about this are a bit nuanced, but for the purposes of the majority of this book, this will be bound to the React component class. So, when we write this.props inside the component, we’re accessing the props property on the component. When we diverge from this rule in later sections, we’ll point it out. For more details on this, check out this page on MDN27 . With our updated app.js file saved, let’s refresh the web browser again: The ProductList component now shows a single product listed, the first object pulled from Seed. We’re getting somewhere interesting. Our Product component is now data-driven. Based on the props it receives it can render any product that we’d like. Our code is poised to have ProductList render any number of products. We just need to configure the component to render some number of Product components, one for each product we’d like to represent on the page. Rendering multiple products To render multiple products, first we’ll have ProductList generate an array of Product components. Each will be derived from an individual object in the Seed array. We’ll use map to do so: 27 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this Your first React Web Application 33 voting_app/public/js/app-4.js class ProductList extends React.Component { render() { const productComponents = Seed.products.map((product) => ( )); The function passed to map returns a Product component. This Product is created just as before with props pulled from the object in Seed. We pass an arrow function to map. Arrow functions were introduced in ES6. For more info, see Appendix B. As such, the productComponents variable ends up being an array of Product components: // Our `productComponents` array [ , , , ] Notably, we’re able to represent the Product component instance in JSX inside of return. It might seem odd at first that we’re able to have a JavaScript array of JSX elements, but remember that Babel will transpile the JSX representation of each Product () into regular JavaScript: Your first React Web Application 34 // What `productComponents` looks like in JavaScript [ React.createElement(Product, { id: 1, ... }), React.createElement(Product, { id: 2, ... }), React.createElement(Product, { id: 3, ... }), React.createElement(Product, { id: 4, ... }) ] Array’s map() Array’s map method takes a function as an argument. It calls this function with each item inside of the array (in this case, each object inside Seed.products) and builds a new array by using the return value from each function call. Because the Seed.products array has four items, map will call this function four times, once for each item. When map calls this function, it passes in as the first argument an item. The return value from this function call is inserted into the new array that map is constructing. After handling the last item, map returns this new array. Here, we’re storing this new array in the variable productComponents. Note the use of the key={'product-' + product.id} prop. React uses this special property to create unique bindings for each instance of the Product component. The key prop is not used by our Product component, but by the React framework. It’s a special property that we discuss deeper in the chapter “Advanced Component Configuration.” For the time being, it’s enough to note that this property needs to be unique per React component in a list. Now, below the declaration of productComponents, we need to modify the return value of render. Before, we were rendering a single Product component. Now, we can render our array productComponents: voting_app/public/js/app-4.js return (
{productComponents}
); Refreshing the page, we’ll see all four products from Seed listed: Your first React Web Application 35 We now have five total React components at work. We have a single parent component, ProductList. ProductList contains four child Product components, one for each product object in the Seed.products array in seed.js: Product components (orange) inside of the ProductList component (red) At the moment, our products aren’t sorted by the number of votes they have. Let’s sort them. We’ll use Array’s sort method to do so. We’ll sort the products first before the line where we build our productComponents array: Your first React Web Application 36 voting_app/public/js/app-5.js class ProductList extends React.Component { render() { const products = Seed.products.sort((a, b) => ( b.votes - a.votes )); const productComponents = products.map((product) => ( ( )); We can now access this function inside Product via this.props.onVote. Let’s write a function inside Product that calls this new prop-function. We’ll name the function handleUpVote(): voting_app/public/js/app-6.js // Inside `Product` handleUpVote() { this.props.onVote(this.props.id); } render() { Your first React Web Application 39 We invoke the prop-function this.props.onVote with the id of the product. Now, we just need to call this function every time the user clicks the caret icon. In React, we can use the special attribute onClick to handle mouse click events. We’ll set the onClick attribute on the a HTML tag that is the up-vote button. We’ll instruct it to call handleUpVote() whenever it is clicked: voting_app/public/js/app-6.js {/* Inside `render` for Product` */}
{this.props.votes}
When the user clicks the up-vote icon, it will trigger a chain of function calls: 1. User clicks the up-vote icon. 2. React invokes Product component’s handleUpVote. 3. handleUpVote invokes its prop onVote. This function lives inside the parent ProductList and logs a message to the console. There’s one last thing we need to do to make this work. Inside the function handleUpVote() we refer to this.props: voting_app/public/js/app-6.js handleUpVote() { this.props.onVote(this.props.id); } Here’s the odd part: When working inside render(), we’ve witnessed that this is always bound to the component. But inside our custom component method handleUpVote(), this is actually null. Binding custom component methods In JavaScript, the special this variable has a different binding depending on the context. For instance, inside render() we say that this is “bound” to the component. Put another way, this “references” the component. Your first React Web Application 40 Understanding the binding of this is one of the trickiest parts of learning JavaScript programming. Given this, it’s fine for a beginner React programmer to not understand all the nuances at first. In short, we want this inside handleUpVote() to reference the component, just like it does inside render(). But why does this inside render() reference the component while this inside handleUpVote() does not? For the render() function, React binds this to the component for us. React specifies a default set of special API methods. render() is one such method. As we’ll see at the end of the chapter, componentDidMount() is another. For each of these special React methods, React will bind the this variable to the component automatically. So, any time we define our own custom component methods, we have to manually bind this to the component ourselves. There’s a pattern that we use to do so. Add the following constructor() function to the top of Product: voting_app/public/js/app-6.js class Product extends React.Component { constructor(props) { super(props); this.handleUpVote = this.handleUpVote.bind(this); } constructor() is a special function in a JavaScript class. JavaScript invokes constructor() whenever an object is created via a class. If you’ve never worked with an object-oriented language before, it’s sufficient to know that React invokes constructor() first thing when initializing our component. React invokes constructor() with the component’s props. Because constructor() is called when initializing our component, we’ll use it for a couple different types of situations in the book. For our current purposes, it’s enough to know that whenever we want to bind custom component methods to a React component class, we can use this pattern: class MyReactComponent extends React.Component { constructor(props) { super(props); // always call this first // custom method bindings here this.someFunction = this.someFunction.bind(this); } } If you’re feeling comfortable reading further details on this pattern, see the aside Binding in constructor(). Your first React Web Application 41 At the end of the chapter, we’ll use an experimental JavaScript feature that allows us to bypass this pattern. However, when working with regular ES7 JavaScript, it’s important to keep this pattern in mind: When defining custom methods on our React component classes, we must perform the binding pattern inside constructor() so that this references our component. Saving our updated app.js, refreshing our web browser, and clicking an up-vote will log some text to our JavaScript console: The events are being propagated up to the parent! ProductList is the owner of the product data. And Product is now informing its parent whenever a user up-votes a product. Our next task is to update the vote count on the product. But where do we perform this update? At the moment, our app doesn’t have a place to store and manage data. Seed should be thought of as a seed of example data, not our app’s datastore. What our app is currently missing is state. Your first React Web Application 42 In fact, while we might be tempted to update the vote count in Seed.products like this: // Would this work? Seed.products.forEach((product) => { if (product.id === productId) { product.votes = product.votes + 1; } }); Doing so wouldn’t work. When updating Seed, our React app would not be informed of the change. On the user interface there would be no indication that the vote count was incremented. Binding in constructor() The first thing we do in constructor() is call super(props). The React.Component class that our Product class is extending defines its own constructor(). By calling super(props), we’re invoking that constructor() function first. Importantly, the constructor() function defined by React.Component will bind this inside our constructor() to the component. Because of this, it’s a good practice to always call super() first whenever you declare a constructor() for your component. After calling super(), we call bind() on our custom component method: this.handleUpVote = this.handleUpVote.bind(this); Function’s bind() method allows you to specify what the this variable inside a function body should be set to. What we’re doing here is a common JavaScript pattern. We’re redefining the component method handleUpVote(), setting it to the same function but bound to this (the component). Now, whenever handleUpVote() executes, this will reference the component as opposed to null. Using state Whereas props are immutable and owned by a component’s parent, state is owned by the component. this.state is private to the component and as we’ll see can be updated with this.setState(). Critically, when the state or props of a component update, the component will re-render itself. Your first React Web Application 43 Every React component is rendered as a function of its this.props and this.state. This rendering is deterministic. This means that given a set of props and a set of state, a React component will always render a single way. As we mentioned at the beginning of the chapter, this approach makes for a powerful UI consistency guarantee. Because we are mutating the data for our products (the number of votes), we should consider this data to be stateful. ProductList will be the owner of this state. It will then pass this state down as props to Product. At the moment, ProductList is reading directly from Seed inside render() to grab the products. Let’s move this data into the component’s state. When adding state to a component, the first thing we do is define what the initial state should look like. Because constructor() is called when initializing our component, it’s the best place to define our initial state. In React components, state is an object. The shape of our ProductList state object will look like this: // Shape of the `ProductList` state object { products: , } We’ll initialize our state to an object with an empty products array. Add this constructor() to ProductList: voting_app/public/js/app-7.js class ProductList extends React.Component { constructor(props) { super(props); this.state = { products: [], }; } componentDidMount() { this.setState({ products: Seed.products }); } Like with our constructor() call in Product, the first line in constructor() is the super(props) call. The first line in any constructor() functions we write for React components will always be this same line. Your first React Web Application 44 Technically, because we don’t supply ProductList any props, we don’t need to propagate the props argument to super(). But it’s a good habit to get into and helps avoid odd bugs in the future. Next, with our state initialized, let’s modify the ProductList component’s render function so that it uses state as opposed to reading from Seed. We read the state with this.state: voting_app/public/js/app-7.js render() { const products = this.state.products.sort((a, b) => ( b.votes - a.votes )); ProductList is driven by its own state now. If we were to save and refresh now, all our products would be missing. We don’t have any mechanisms in ProductList that add products to its state. Setting state with this.setState() It’s good practice to initialize components with “empty” state as we’ve done here. We explore the reasoning behind this when working asynchronously with servers in the chapter “Components & Servers.” However, after our component is initialized, we want to seed the state for ProductList with the data in Seed. React specifies a set of lifecycle methods. React invokes one lifecycle method, componentDidMount(), after our component has mounted to the page. We’ll seed the state for ProductList inside this method. We explore the rest of the lifecycle methods in the chapter “Advanced Component Configuration.” Knowing this, we might be tempted to set the state to Seed.products inside componentDidMount() like this: Your first React Web Application 45 class ProductList extends React.Component { // ... // Is this valid ? componentDidMount() { this.state = Seed.products; } // ... } However, this is invalid. The only time we can modify the state in this manner is in constructor(). For all state modifications after the initial state, React provides components the method this.setState(). Among other things, this method triggers the React component to re-render which is essential after the state changes. Never modify state outside of this.setState(). This function has important hooks around state modification that we would be bypassing. We discuss state management in detail throughout the book. Add componentDidMount() to ProductList now. We’ll use setState() to seed the component’s state: voting_app/public/js/app-8.js class ProductList extends React.Component { constructor(props) { super(props); this.state = { products: [], }; } componentDidMount() { this.setState({ products: Seed.products }); } The component will mount with an empty state this.state.products array. After mounting, we populate the state with data from Seed. The component will re-render and our products will be displayed. This happens at a speed that is imperceptible to the user. If we save and refresh now, we see that the products are back. Your first React Web Application 46 Updating state and immutability Now that ProductList is managing the products in state, we’re poised to make modifications to this data in response to user input. Specifically, we want to increment the votes property on a product when the user votes for it. We just discussed that we can only make state modifications using this.setState(). So while a component can update its state, we should treat the this.state object as immutable. As touched on earlier, if we treat an array or object as immutable we never make modifications to it. For example, let’s say we have an array of numbers in state: this.setState({ nums: [ 1, 2, 3 ]}); If we want to update the state’s nums array to include a 4, we might be tempted to use push() like this: this.setState({ nums: this.state.nums.push(4) }); On the surface, it might appear as though we’ve treated this.state as immutable. However, the push() method modifies the original array: console.log(this.state.nums); // [ 1, 2, 3 ] this.state.nums.push(4); console.log(this.state.nums); // [ 1, 2, 3, 4] <-- Uh-oh! Although we invoke this.setState() immediately after we push 4 onto the array, we’re still modifying this.state outside of setState() and this is bad practice. Part of the reason this is bad practice is because setState() is actually asynchronous. There is no guarantee when React will update the state and re-render our component. We touch on this in the “Advanced Component Configuration” chapter. So, while we eventually called this.setState(), we unintentionally modified the state before that. This next approach doesn’t work either: Your first React Web Application 47 const nextNums = this.state.nums; nextNums.push(4); console.log(nextNums); // [ 1, 2, 3, 4] console.log(this.state.nums); // [ 1, 2, 3, 4] <-- Nope! Our new variable nextNums references the same array as this.state.nums in memory: Both variables reference the same array in memory So when we modify the array with push(), we’re modifying the same array that this.state.nums is pointing to. Instead, we can use Array’s concat(). concat() creates a new array that contains the elements of the array it was called on followed by the elements passed in as arguments. With concat(), we can avoid mutating state: console.log(this.state.nums); // [ 1, 2, 3 ] const nextNums = this.state.nums.concat(4); console.log(nextNums); // [ 1, 2, 3, 4] console.log(this.state.nums); // [ 1, 2, 3 ] <-- Unmodified! We touch on immutability throughout the book. While you might be able to “get away” with mutating the state in many situations, it’s better practice to treat state as immutable. Treat the state object as immutable. It’s important to understand which Array and Object methods modify the objects they are called on. Your first React Web Application 48 If an array is passed in as an argument to concat(), its elements are appended to the new array. For example: > [ 1, 2, 3 ].concat([ 4, 5 ]); => [ 1, 2, 3, 4, 5 ] Knowing that we want to treat the state as immutable, the following approach to handling up-votes would be problematic: // Inside `ProductList` // Invalid handleProductUpVote(productId) { const products = this.state.products; products.forEach((product) => { if (product.id === productId) { product.votes = product.votes + 1; } }); this.setState({ products: products, }); } When we initialize products to this.state.products, product references the same array in memory as this.state.products: Both variables reference the same array in memory Your first React Web Application 49 So, when we modify a product object by incrementing its vote count inside forEach(), we’re modifying the original product object in state. Instead, we should create a new array of products. And if we modify one of the product objects, we should modify a clone of the object as opposed to the original one. Let’s see what a handleProductUpVote() implementation looks like that treats state as immutable. We’ll see it in full then break it down: voting_app/public/js/app-9.js // Inside `ProductList` handleProductUpVote(productId) { const nextProducts = this.state.products.map((product) => { if (product.id === productId) { return Object.assign({}, product, { votes: product.votes + 1, }); } else { return product; } }); this.setState({ products: nextProducts, }); } First, we use map() to traverse the products array. Importantly, map() returns a new array as opposed to modifying the array this.state.products. Next, we check if the current product matches productId. If it does, we create a new object, copying over the properties from the original product object. We then overwrite the votes property on our new product object. We set it to the incremented vote count. We do this using Object’s assign() method: voting_app/public/js/app-9.js if (product.id === productId) { return Object.assign({}, product, { votes: product.votes + 1, }); We use Object.assign() a lot for avoiding mutating objects. For more details on the method, check out Appendix B. If the current product is not the one specified by productId, we return it unmodified: Your first React Web Application 50 voting_app/public/js/app-9.js } else { return product; } Finally, we use setState() to update the state. map() is creating a new array. So you might ask: Why can’t we modify the product object directly? Like this: if (product.id === productId) { product.votes = product.votes + 1; } While we’re creating a new array, the variable product here still references the product object sitting on the original array in state. Therefore, if we make changes to it we’ll be modifying the object in state. So we use Object.assign() to clone the original into a new object and then modify the votes property on that new object. Our state update for up-votes is in place. There’s one last thing we have to do: Our custom component method handleProductUpVote() is now referencing this. We need to add a bind() call like the one we have for handleUpVote() in Product: voting_app/public/js/app-9.js class ProductList extends React.Component { constructor(props) { super(props); this.state = { products: [], }; this.handleProductUpVote = this.handleProductUpVote.bind(this); } Now this in handleProductUpVote() references our component. Our app should finally be responsive to user interaction. Save app.js, refresh the browser, and cross your fingers: Your first React Web Application 51 At last, the vote counters are working! Try up-voting a product a bunch of times and notice how it immediately jumps above products with lower vote counts. Refactoring with the Babel plugin transform-class-properties In this last section, we’ll explore a possible refactor that we can make to our class components using an experimental JavaScript feature. For reasons you’ll soon see, this feature is popular among React developers. Because the community is still adopting this feature, we expose you to both class component styles throughout the book. We’re able to access this feature using Babel’s library of plugins and presets. Babel plugins and presets We’ve been using Babel in this project to give us the ability to write modern JavaScript that will run in a majority of browsers on the web. Specifically, our code has been using Babel to convert ES6 syntax and JSX into vanilla ES5 JavaScript. There’s a few ways to integrate Babel into your project. We’ve been using babel-standalone which allows us to setup Babel quickly for use directly in the browser. Your first React Web Application 52 babel-standalone by default uses two presets. In Babel, a preset is a set of plugins used to support particular language features. The two presets Babel has been using by default: • es201528 : Adds support for ES2015 (or ES6) JavaScript • react29 : Adds support for JSX Remember: ES2015 is just another name used for ES6. We let Babel use the default es2015 preset for this project because we don’t need or use either of ES7’s two new features. JavaScript is an ever-changing language. At its current pace, new syntax will be ratified for adoption on a yearly basis. Because JavaScript will continue to evolve, tools like Babel are here to stay. Developers want to take advantage of the latest language features. But it takes time for browsers to update their JavaScript engines. And it takes even more time for the majority of the public to upgrade their browsers to the latest versions. Babel closes this gap. It enables a codebase to evolve along with JavaScript without leaving older browsers behind. Beyond ES7, proposed JavaScript features can exist in various stages. A feature can be an experimental proposal, one that the community is still working out the details for (“stage 1”). Experimental proposals are at risk of being dropped or modified at any time. Or a feature might already be “ratified,” which means it will be included in the next release of JavaScript (“stage 4”). We can customize Babel with presets and plugins to take advantage of these upcoming or experimental features. In this book, we generally avoid features that are experimental. However, there is one feature that looks to be ratified that we make an exception for: property initializers. We avoid features that are experimental because we don’t want to teach features that might be modified or dropped. For your own projects, it’s up to you and your team to decide how “strict” you want to be about the JavaScript features that you use. If you’d like to read more about the various Babel presets and plugins, check out the docs30 . Property initializers Property initializers are detailed in the proposal “ES Class Fields & Static Properties31 .” While an experimental feature that has yet to be ratified, property initializers offer a compelling syntax that 28 https://babeljs.io/docs/plugins/preset-es2015/ https://babeljs.io/docs/plugins/preset-react/ 30 https://babeljs.io/docs/plugins/ 31 https://github.com/tc39/proposal-class-public-fields 29 Your first React Web Application 53 greatly simplify React class components. This feature works so well with React that the Facebook team has written about using it internally32 . Property initializers are available in the Babel plugin transform-class-properties. Recall that we specified this plugin for app.js inside index.html: Therefore, we’re ready to use this feature in our code. The best way to understand what this feature gives us is to see it in action. Refactoring Product Inside Product, we defined the custom component method handleUpVote. As we discussed, because handleUpVote is not part of the standard React component API, React does not bind this inside the method to our component. So we had to perform a manual binding trick inside constructor: voting_app/public/js/app-9.js class Product extends React.Component { constructor(props) { super(props); this.handleUpVote = this.handleUpVote.bind(this); } handleUpVote() { this.props.onVote(this.props.id); } render() { With the transform-class-properties plugin, we can write handleUpVote as an arrow function. This will ensure this inside the function is bound to the component, as expected: 32 https://babeljs.io/blog/2015/06/07/react-on-es6-plus Your first React Web Application 54 voting_app/public/js/app-complete.js class Product extends React.Component { handleUpVote = () => ( this.props.onVote(this.props.id) ); render() { Using this feature, we can drop constructor(). There is no need for the manual binding call. Note that methods that are part of the standard React API, like render(), will remain as class methods. If we write a custom component method in which we want this bound to the component, we write it as an arrow function. Refactoring ProductList We can give the same treatment to handleProductUpVote inside ProductList. In addition, property initializers give us an alternative way to define the initial state of a component. Before, we used constructor() in ProductList to both bind handleProductUpVote to the component and define the component’s initial state: class ProductList extends React.Component { constructor(props) { super(props); this.state = { products: [], }; this.handleProductUpVote = this.handleProductUpVote.bind(this); } With property initializers, we no longer need to use constructor. Instead, we can define the initial state like this: Your first React Web Application 55 voting_app/public/js/app-complete.js class ProductList extends React.Component { state = { products: [], }; And, if we define handleProductUpVote as an arrow function, this will be bound to the component as desired: voting_app/public/js/app-complete.js handleProductUpVote = (productId) => { const nextProducts = this.state.products.map((product) => { if (product.id === productId) { return Object.assign({}, product, { votes: product.votes + 1, }); } else { return product; } }); this.setState({ products: nextProducts, }); } In sum, we can use property initializers to make two refactors to our React components: 1. We can use arrow functions for custom component methods (and avoid having to bind this) 2. We can define the initial state outside of constructor() We expose you to both approaches in this book as both are in widespread use. Each project will be consistent as to whether or not it uses transform-class-properties. You’re welcome to continue to use vanilla ES6 in your own projects. However, the terseness afforded by transform-classproperties is often too attractive to pass up. Using ES6/ES7 with additional presets or plugins is sometimes referred to by the community as “ES6+/ES7+”. Your first React Web Application 56 Congratulations! We just wrote our first React app. There are a ton of powerful features we’ve yet to go over, yet all of them build upon the core fundamentals we just covered: 1. 2. 3. 4. 5. 6. 7. We think about and organize our React apps as components Using JSX inside the render method Data flows from parent to children through props Event flows from children to parent through functions Utilizing React lifecycle methods Stateful components and how state is different from props How to manipulate state while treating it as immutable Onward! Components A time-logging app In the last chapter, we described how React organizes apps into components and how data flows between parent and child components. And we discussed core concepts such as how we manage state and pass data between components using props. In this chapter, we construct a more intricate application. We investigate a pattern that you can use to build React apps from scratch and then put those steps to work to build an interface for managing timers. In this time-tracking app, a user can add, delete, and modify various timers. Each timer corresponds to a different task that the user would like to keep time for: This app will have significantly more interactive capabilities than the one built in the last chapter. This will present us with some interesting challenges that will deepen our familiarity with React’s core concepts. 58 Components Getting started As with all chapters, before beginning make sure you’ve downloaded the book’s sample code and have it at the ready. Previewing the app Let’s begin by playing around with a completed implementation of the app. In your terminal, cd into the time_tracking_app directory: $ cd time_tracking_app Use npm to install all the dependencies: $ npm install Then boot the server: $ npm start Now you can view the app in your browser. Open your browser and enter the URL http://localhost:3000. Play around with it for a few minutes to get a feel for all the functionality. Refresh and note that your changes have been persisted. Note that this app uses a different web server than the one used in the voting app. The app won’t automatically launch in your browser or automatically refresh when you make changes. Prepare the app In your terminal, run ls to see the project’s layout: 59 Components $ ls README.md data.json nightwatch.json node_modules/ package.json public/ semantic.json server.js tests/ There are a few organizational changes from the last project. First, notice that there is now a server.js in this project. In the last chapter, we used a pre-built Node package (called live-server) to serve our assets. This time we have a custom-built server which serves our assets and also adds a persistence layer. We will cover the server in detail in the next chapter. When you visit a website, assets are the files that your browser downloads and uses to display the page. index.html is delivered to the browser and inside its head tags it specifies which additional files from the server the browser needs to download. In the last project, our assets were index.html as well as our stylesheets and images. In this project, everything under public/ is an asset. In the voting app, we loaded all of our app’s initial data from a JavaScript variable, loaded in the file seed.js. This time, we’re going to eventually store it in the text file data.json. This brings the behavior a bit closer to a database. By using a JSON file, we can make edits to our data that will be persisted even if the app is closed. JSON stands for JavaScript Object Notation. JSON enables us to serialize a JavaScript object and read/write it from a text file. If you’re not familiar with JSON, take a look at data.json. Pretty recognizable, right? JavaScript has a built-in mechanism to parse the contents of this file and initialize a JavaScript object with its data. Peek inside public: Components 60 $ cd public $ ls The structure here is the same as the last project: favicon.ico index.html js/ semantic/ style.css vendor/ Again, index.html is the centerpiece of the app. It’s where we include all of our JavaScript and CSS files and where we specify the DOM node where we’ll ultimately mount our React app. We’re using SemanticUI again here for styling. All of SemanticUI’s assets are underneath semantic/. All our JavaScript files are inside of js/: $ ls js/ app-1.js app-2.js app-3.js app-4.js app-5.js app-6.js app-7.js app-8.js app-9.js app-complete.js app.js client.js helpers.js We’ll be building the app inside app.js. The completed version of the app which we reach in the next chapter is inside app-complete.js. Each step we take along the way is included here: app-1.js, app-2.js, and so forth. Like the last chapter, code examples in the book are titled with the file in which you can find that example. Furthermore, we’ll be using a couple additional JavaScript files for this project. As we’ll see, client.js contains functions that we’ll use to interface with our server in the next chapter. helpers.js contains some helper functions that our components will use. As before, our first step is to ensure app-complete.js is no longer loaded in index.html. We’ll instead load the empty file app.js. Open up index.html: Components 61 time_tracking_app/public/index.html Project Two: Timers

Timers

Overall, this file is very similar to the one we used in our voting app. We load in our dependencies within the head tags (the assets). Inside of body we have a few elements. This div is where we will ultimately mount our React app: Components 62 time_tracking_app/public/index.html
And this script tag is where we instruct the browser to load app.js into the page: time_tracking_app/public/index.html We’re using the Babel plugin transform-class-properties again in this chapter. We discussed this plugin at the end of the previous chapter. Do as the comment says and delete the script tag that loads app-complete.js: Save index.html. If you reload the page now, you’ll see the app has disappeared. Breaking the app into components As we did with our last project, we begin by breaking our app down into its components. Again, visual components often map tightly to their respective React components. Let’s examine the interface of our app: Components 63 In the last project, we had ProductList and Product components. The first contained instances of the second. Here, we spot the same pattern, this time with TimerList and Timer components: Components 64 However, there’s one subtle difference: This list of timers has a little “+” icon at the bottom. As we saw, we’re able to add new timers to the list using this button. So, in reality, the TimerList component isn’t just a list of timers. It also contains a widget to create new timers. Think about components as you would functions or objects. The single responsibility principle33 applies. A component should, ideally, only be responsible for one piece of functionality. So, the proper response here is for us to shrink TimerList back into its responsibility of just listing timers and to nest it under a parent component. We’ll call the parent TimersDashboard. TimersDashboard will have TimerList and the “+”/create form widget as children: 33 https://en.wikipedia.org/wiki/Single_responsibility_principle 65 Components Not only does this separation of responsibilities keep components simple, but it often also improves their re-usability. In the future, we can now drop the TimerList component anywhere in the app where we just want to display a list of timers. This component no longer carries the responsibility of also creating timers, which might be a behavior we want to have for just this dashboard view. How you name your components is indeed up to you, but having some consistent rules around language as we do here will greatly improve code clarity. In this case, developers can quickly reason that any component they come across that ends in the word List simply renders a list of children and no more. The “+”/create form widget is interesting because it has two distinct representations. When the “+” button is clicked, the widget transmutes into a form. When the form is closed, the widget transmutes back into a “+” button. There are two approaches we could take. The first one is to have the parent component, TimersDashboard, decide whether or not to render a “+” component or a form component based on some piece of stateful data. It could swap between the two children. However, this adds more responsibility to TimersDashboard. The alternative is to have a new child component own the single responsibility of determining whether or not to display a “+” button or a create timer form. We’ll call it ToggleableTimerForm. As a child, it can either render the component TimerForm or the HTML markup for the “+” button. At this point, we’ve carved out four components: 66 Components Now that we have a sharp eye for identifying overburdened components, another candidate should catch our eye: A single timer: Displaying time (left) vs. edit form (right) The timer itself has a fair bit of functionality. It can transform into an edit form, delete itself, and start and stop itself. Do we need to break this up? And if so, how? Displaying a timer and editing a timer are indeed two distinct UI elements. They should be two distinct React components. Like ToggleableTimerForm, we need some container component that renders either the timer’s face or its edit form depending on if the timer is being edited. Components 67 We’ll call this EditableTimer. The child of EditableTimer will then be either a Timer component or the edit form component. The form for creating and editing timers is very similar, so let’s assume that we can use the component TimerForm in both contexts: As for the other functionality of the timer, like the start and stop buttons, it’s a bit tough to determine at this point whether or not they should be their own components. We can trust that the answers will be more apparent after we’ve written some code. Working back up the component tree, we can see that the name TimerList would be a misnomer. It really is a EditableTimerList. Everything else looks good. So, we have our final component hierarchy, with some ambiguity around the final state of the timer component: Components • TimersDashboard: Parent container – EditableTimerList: Displays a list of timer containers * EditableTimer: Displays either a timer or a timer’s edit form · Timer: Displays a given timer · TimerForm: Displays a given timer’s edit form – ToggleableTimerForm: Displays a form to create a new timer * TimerForm (not displayed): Displays a new timer’s create form Represented as a hierarchical tree: 68 69 Components In our previous app, ProductList handled not only rendering components, but also the responsibility of handling up-votes and talking to the store. While this worked for that app, you can imagine that as a codebase expands, there may come a day where we’d want to free ProductList of this responsibility. For example, imagine if we added a “sort by votes” feature to ProductList. What if we wanted some pages to be sortable (category pages) but other pages to be static (top 10)? We’d want to “hoist” sort responsibility up to a parent component and make ProductList the straightforward list renderer that it should be. This new parent component could then include the sorting-widget component and then pass down the ordered products to the ProductList component. The steps for building React apps from scratch Now that we have a good understanding of the composition of our components, we’re ready to build a static version of our app. Ultimately, our top-level component will communicate with a server. The Components 70 server will be the initial source of state, and React will render itself according to the data the server provides. Our app will also send updates to the server, like when a timer is started: However, it will simplify things for us if we start off with static components, as we did in the last chapter. Our React components will do little more than render HTML. Clicking on buttons won’t yield any behavior as we will not have wired up any interactivity. This will enable us to lay the framework for the app, getting a clear idea of how the component tree is organized. Next, we can determine what the state should be for the app and in which component it should live. We’ll start off by just hard-coding the state into the components instead of loading it from the server. At that point, we’ll have the data flow from parent to child in place. Then we can add inverse data flow, propagating events from child to parent. Finally, we’ll modify the top-level component to have it communicate with the server. In fact, this follows from a handy framework for developing a React app from scratch: 1. 2. 3. 4. 5. 6. Break the app into components Build a static version of the app Determine what should be stateful Determine in which component each piece of state should live Hard-code initial states Add inverse data flow Components 71 7. Add server communication We followed this pattern in the last project: 1. Break the app into components We looked at the desired UI and determined we wanted ProductList and Product components. 2. Build a static version of the app Our components started off without using state. Instead, we had ProductList pass down static props to Product. 3. Determine what should be stateful In order for our application to become interactive, we had to be able to modify the vote property on each product. Each product had to be mutable and therefore stateful. 4. Determine in which component each piece of state should live ProductList managed the voting state using React component class methods. 5. Hard-code initial state When we re-wrote ProductList to use this.state, we seeded it from Seed.products. 6. Add inverse data flow We defined the handleUpVote function in ProductList and passed it down in props so that each Product could inform ProductList of up-vote events. 7. Add server communication We did not add a server component to our last app, but we will be doing so in this one. If steps in this process aren’t completely clear right now, don’t worry. The purpose of this chapter is to familiarize yourself with this procedure. We’ve already covered step (1) and have a good understanding of all of our components, save for some uncertainty down at the Timer component. Step (2) is to build a static version of the app. As in the last project, this amounts to defining React components, their hierarchy, and their HTML representation. We completely avoid state for now. Step 2: Build a static version of the app TimersDashboard Let’s start off with the TimersDashboard component. Again, all of our React code for this chapter will be inside of the file public/app.js. We’ll begin by defining a familiar function, render(): 72 Components time_tracking_app/public/js/app-1.js class TimersDashboard extends React.Component { render() { return (
); } } This component renders its two child components nested under div tags. TimersDashboard passes down one prop to ToggleableTimerForm: isOpen. This is used by the child component to determine whether to render a “+” or TimerForm. When ToggleableTimerForm is “open” the form is being displayed. As in the last chapter, don’t worry about the className attribute on the div tags. This will ultimately define the class on HTML div elements and is purely for styling purposes. In this example, classes like ui three column centered grid all come from the CSS framework Semantic UI34 . The framework is included in the head of index.html. We will define EditableTimerList next. We’ll have it render two EditableTimer components. One will end up rendering a timer’s face. The other will render a timer’s edit form: time_tracking_app/public/js/app-1.js class EditableTimerList extends React.Component { render() { return (
); } } We’re passing five props to each child component. The key difference between the two EditableTimer components is the value being set for editFormOpen. We’ll use this boolean to instruct EditableTimer which sub-component to render. The purpose of the prop runningSince will be covered later on in the app’s development. EditableTimer EditableTimer returns either a TimerForm or a Timer based on the prop editFormOpen: time_tracking_app/public/js/app-1.js class EditableTimer extends React.Component { render() { if (this.props.editFormOpen) { return ( ); } else { return ( ); } } } Note that title and project are passed down as props to TimerForm. This will enable the component to fill in these fields with the timer’s current values. TimerForm We’ll build an HTML form that will have two input fields. The first input field is for the title and the second is for the project. It also has a pair of buttons at the bottom: time_tracking_app/public/js/app-1.js class TimerForm extends React.Component { render() { const submitText = this.props.title ? 'Update' : 'Create'; return (
75 Components
); } } Look at the input tags. We’re specifying that they have type of text and then we are using the React property defaultValue. When the form is used for editing as it is here, this sets the fields to the current values of the timer as desired. Later, we’ll use TimerForm again within ToggleableTimerForm for creating timers. ToggleableTimerForm will not pass TimerForm any props. this.props.title and this.props.project will therefore return undefined and the fields will be left empty. At the beginning of render(), before the return statement, we define a variable submitText. This variable uses the presence of this.props.title to determine what text the submit button at the bottom of the form should display. If title is present, we know we’re editing an existing timer, so it displays “Update.” Otherwise, it displays “Create.” With all of this logic in place, TimerForm is prepared to render a form for creating a new timer or editing an existing one. We used an expression with the ternary operator to set the value of submitText. The syntax is: 1 condition ? expression1 : expression2 If the condition is true, the operator returns the value of expression1. Otherwise, it returns the value of expression2. In our example, the variable submitText is set to the returned expression. ToggleableTimerForm Let’s turn our attention next to ToggleableTimerForm. Recall that this is a wrapper component around TimerForm. It will display either a “+” or a TimerForm. Right now, it accepts a single prop, isOpen, from its parent that instructs its behavior: Components 76 time_tracking_app/public/js/app-1.js class ToggleableTimerForm extends React.Component { render() { if (this.props.isOpen) { return ( ); } else { return (
); } } } As noted earlier, TimerForm does not receive any props from ToggleableTimerForm. As such, its title and project fields will be rendered empty. The return statement under the else block is the markup to render a “+” button. You could make a case that this should be its own React component (say PlusButton) but at present we’ll keep the code inside ToggleableTimerForm. Timer Time for the Timer component. Again, don’t worry about all the div and span elements and className attributes. We’ve provided these for styling purposes: time_tracking_app/public/js/app-1.js class Timer extends React.Component { render() { const elapsedString = helpers.renderElapsedString(this.props.elapsed); return (
{this.props.title}
77 Components
{this.props.project}

{elapsedString}

Start
); } } elapsed in this app is in milliseconds. This is the representation of the data that React will keep. This is a good representation for machines, but we want to show our carbon-based users a more readable format. We use a function defined in helpers.js, renderElapsedString(). You can pop open that file if you’re curious about how it’s implemented. The string it renders is in the format ‘HH:MM:SS’. Note that we could store elapsed in seconds as opposed to milliseconds, but JavaScript’s time functionality is all in milliseconds. We keep elapsed consistent with this for simplicity. As a bonus, our timers are also slightly more accurate, even though they round to seconds when displayed to the user. Render the app With all of the components defined, the last step before we can view our static app is to ensure we call ReactDOM#render(). Put this at the bottom of the file: 78 Components time_tracking_app/public/js/app-1.js ReactDOM.render( , document.getElementById('content') ); Again, we specify with ReactDOM#render() which React component we want to render and where in our HTML document (index.html) to render it. In this case, we’re rendering TimersDashboard at the div with the id of content. Try it out Save app.js and boot the server (npm start). Find it at localhost:3000: Tweak some of the props and refresh to see the results. For example: • Flip the prop passed down to ToggleableTimerForm from true to false and see the “+” button render. Components 79 • Flip parameters on editFormOpen and witness EditableTimer flip the child it renders accordingly. Let’s review all of the components represented on the page: Inside TimersDashboard are two child components: EditableTimerList and ToggleableTimerForm. EditableTimerList contains two EditableTimer components. The first of these has a Timer component as a child and the second a TimerForm. These bottom-level components — also known as leaf components — hold the majority of the page’s HTML. This is generally the case. The components above leaf components are primarily concerned with orchestration. ToggleableTimerForm renders a TimerForm. Notice how the two forms on the page have different language for their buttons, as the first is updating and the second is creating. Step 3: Determine what should be stateful In order to bestow our app with interactivity, we must evolve it from its static existence to a mutable one. The first step is determining what, exactly, should be mutable. Let’s start by collecting all of the data that’s employed by each component in our static app. In our static app, data will be wherever we are defining or using props. We will then determine which of that data should be stateful. TimersDashboard In our static app, this declares two child components. It sets one prop, which is the isOpen boolean that is passed down to ToggleableTimerForm. EditableTimerList This declares two child components, each which have props corresponding to a given timer’s properties. EditableTimer This uses the prop editFormOpen. Timer This uses all the props for a timer. TimerForm This has two interactive input fields, one for title and one for project. When editing an existing timer, these fields are initialized with the timer’s current values. State criteria We can apply criteria to determine if data should be stateful: 80 Components These questions are from the excellent article by Facebook called “Thinking In React”. You can read the original article here35 . 1. Is it passed in from a parent via props? If so, it probably isn’t state. A lot of the data used in our child components are already listed in their parents. This criterion helps us de-duplicate. For example, “timer properties” is listed multiple times. When we see the properties declared in EditableTimerList, we can consider it state. But when we see it elsewhere, it’s not. 2. Does it change over time? If not, it probably isn’t state. This is a key criterion of stateful data: it changes. 3. Can you compute it based on any other state or props in your component? If so, it’s not state. For simplicity, we want to strive to represent state with as few data points as possible. Applying the criteria TimersDashboard • isOpen boolean for ToggleableTimerForm Stateful. The data is defined here. It changes over time. And it cannot be computed from other state or props. EditableTimerList • Timer properties Stateful. The data is defined in this component, changes over time, and cannot be computed from other state or props. EditableTimer • editFormOpen for a given timer Stateful. The data is defined in this component, changes over time, and cannot be computed from other state or props. Timer 35 https://facebook.github.io/react/docs/thinking-in-react.html Components 81 • Timer properties In this context, not stateful. Properties are passed down from the parent. TimerForm We might be tempted to conclude that TimerForm doesn’t manage any stateful data, as title and project are props passed down from the parent. However, as we’ll see, forms are special state managers in their own right. So, outside of TimerForm, we’ve identified our stateful data: • The list of timers and properties of each timer • Whether or not the edit form of a timer is open • Whether or not the create form is open Step 4: Determine in which component each piece of state should live While the data we’ve determined to be stateful might live in certain components in our static app, this does not indicate the best position for it in our stateful app. Our next task is to determine the optimal place for each of our three discrete pieces of state to live. This can be challenging at times but, again, we can apply the following steps from Facebook’s guide “Thinking in React36 ” to help us with the process: For each piece of state: • Identify every component that renders something based on that state. • Find a common owner component (a single component above all the components that need the state in the hierarchy). • Either the common owner or another component higher up in the hierarchy should own the state. • If you can’t find a component where it makes sense to own the state, create a new component simply for holding the state and add it somewhere in the hierarchy above the common owner component. Let’s apply this method to our application: 36 https://facebook.github.io/react/docs/thinking-in-react.html Components 82 The list of timers and properties of each timer At first glance, we may be tempted to conclude that TimersDashboard does not appear to use this state. Instead, the first component that uses it is EditableTimerList. This matches the location of the declaration of this data in our static app. Because ToggleableTimerForm doesn’t appear to use the state either, we might deduce that EditableTimerList must then be the common owner. While this may be the case for displaying timers, modifying them, and deleting them, what about creates? ToggleableTimerForm does not need the state to render, but it can affect state. It needs to be able to insert a new timer. It will propagate the data for the new timer up to TimersDashboard. Therefore, TimersDashboard is truly the common owner. It will render EditableTimerList by passing down the timer state. It can the handle modifications from EditableTimerList and creates from ToggleableTimerForm, mutating the state. The new state will flow downward through EditableTimerList. Whether or not the edit form of a timer is open In our static app, EditableTimerList specifies whether or not a EditableTimer should be rendered with its edit form open. Technically, though, this state could just live in each individual EditableTimer. No parent component in the hierarchy depends on this data. Storing the state in EditableTimer will be fine for our current needs. But there are a few requirements that might require us to “hoist” this state up higher in the component hierarchy in the future. For instance, what if we wanted to impose a restriction such that only one edit form could be open at a time? Then it would make sense for EditableTimerList to own the state, as it would need to inspect it to determine whether to allow a new “edit form open” event to succeed. If we wanted to allow only one form open at all, including the create form, then we’d hoist the state up to TimersDashboard. Visibility of the create form TimersDashboard doesn’t appear to care about whether ToggleableTimerForm is open or closed. It feels safe to reason that the state can just live inside ToggleableTimerForm itself. So, in summary, we’ll have three pieces of state each in three different components: • Timer data will be owned and managed by TimersDashboard. • Each EditableTimer will manage the state of its timer edit form. • The ToggleableTimerForm will manage the state of its form visibility. Components 83 Step 5: Hard-code initial states We’re now well prepared to make our app stateful. At this stage, we won’t yet communicate with the server. Instead, we’ll define our initial states within the components themselves. This means hard-coding a list of timers in the top-level component, TimersDashboard. For our two other pieces of state, we’ll have the components’ forms closed by default. After we’ve added initial state to a parent component, we’ll make sure our props are properly established in its children. Adding state to TimersDashboard Start by modifying TimersDashboard to hold the timer data directly inside the component: time_tracking_app/public/js/app-2.js class TimersDashboard extends React.Component { state = { timers: [ { title: 'Practice squat', project: 'Gym Chores', id: uuid.v4(), elapsed: 5456099, runningSince: Date.now(), }, { title: 'Bake squash', project: 'Kitchen Chores', id: uuid.v4(), elapsed: 1273998, runningSince: null, }, ], }; render() { return (
84 Components
); } } We’re leaning on the Babel plugin transform-class-properties to give us the property initializers syntax. We set the initial state to an object with the key timers. timers points to an array with two hard-coded timer objects. We discuss property initializers in the previous chapter. Below, in render, we pass down state.timers to EditableTimerList. For the id property, we’re using a library called uuid. We load this library in index.html. We use uuid.v4() to randomly generate a Universally Unique IDentifier37 for each item. A UUID is a string that looks like this: 2030efbd-a32f-4fcc-8637-7c410896b3e3 Receiving props in EditableTimerList EditableTimerList receives the list of timers as a prop, timers. Modify that component to use those props: time_tracking_app/public/js/app-2.js class EditableTimerList extends React.Component { render() { const timers = this.props.timers.map((timer) => ( )); return (
{timers}
); } } Hopefully this looks familiar. We’re using map on the timers array to build a list of EditableTimer components. This is exactly how we built our list of Product components inside ProductList in the last chapter. We pass the id down to EditableTimer as well. This is a bit of eager preparation. Remember how Product communicated up to ProductList by calling a function and passing in its id? It’s safe to assume we’ll be doing this again. Props vs. state With your renewed understanding of React’s state paradigm, let’s reflect on props again. Remember, props are state’s immutable accomplice. What existed as mutable state in TimersDashboard is passed down as immutable props to EditableTimerList. We talked at length about what qualifies as state and where state should live. Mercifully, we do not need to have an equally lengthy discussion about props. Once you understand state, you can see how props act as its one-way data pipeline. State is managed in some select parent components and then that data flows down through children as props. If state is updated, the component managing that state re-renders by calling render(). This, in turn, causes any of its children to re-render as well. And the children of those children. And on and on down the chain. Let’s continue our own march down the chain. Adding state to EditableTimer In the static version of our app, EditableTimer relied on editFormOpen as a prop to be passed down from the parent. We decided that this state could actually live here in the component itself. We’ll set the initial value of editFormOpen to false, which means that the form starts off as closed. We’ll also pass the id property down the chain: Components 86 time_tracking_app/public/js/app-2.js class EditableTimer extends React.Component { state = { editFormOpen: false, }; render() { if (this.state.editFormOpen) { return ( ); } else { return ( ); } } } Timer remains stateless If you look at Timer, you’ll see that it does not need to be modified. It has been using exclusively props and is so far unaffected by our refactor. Adding state to ToggleableTimerForm We know that we’ll need to tweak ToggleableTimerForm as we’ve assigned it some stateful responsibility. We want to have the component manage the state isOpen. Because this state is isolated to this component, let’s also add our app’s first bit of interactivity while we’re here. Let’s start by initializing the state. We want the component to initialize to a closed state: Components 87 time_tracking_app/public/js/app-2.js class ToggleableTimerForm extends React.Component { state = { isOpen: false, }; Next, let’s define a function that will toggle the state of the form to open: time_tracking_app/public/js/app-2.js handleFormOpen = () => { this.setState({ isOpen: true }); }; render() { As we explored at the end of the last chapter, we need to write this function as an arrow function in order to ensure this inside the function is bound to the component. React will automatically bind class methods corresponding to the component API (like render and componentDidMount) to the component for us. As a refresher, without the property initializer feature we’d write our custom component method like this: handleFormOpen() { this.setState({ isOpen: true }); } Our next step would be to bind this method to the component inside the constructor, like this: constructor(props) { super(props); this.handleFormOpen = this.handleFormOpen.bind(this); } This is a perfectly valid approach and does not use any features beyond ES7. However, we’ll be using property initializers for this project. While we’re here, we can also add a little bit of interactivity: Components 88 time_tracking_app/public/js/app-2.js render() { if (this.state.isOpen) { return ( ); } else { return (
); } } Like the up-vote button in the last app, we use the onClick property on button to invoke the function handleFormOpen(). handleFormOpen() modifies the state, setting isOpen to true. This causes the component to re-render. When render() is called this second time around, this.state.isOpen is true and ToggleableTimerForm renders TimerForm. Neat. Adding state to TimerForm We mentioned earlier that TimerForm would manage state as it includes a form. In React, forms are stateful. Recall that TimerForm includes two input fields: 89 Components These input fields are modifiable by the user. In React, all modifications that are made to a component should be handled by React and kept in state. This includes changes like the modification of an input field. By having React manage all modifications, we guarantee that the visual component that the user is interacting with on the DOM matches the state of the React component behind the scenes. The best way to understand this is to see what it looks like. To make these input fields stateful, let’s first initialize state at the top of the component: time_tracking_app/public/js/app-2.js class TimerForm extends React.Component { state = { title: this.props.title || '', project: this.props.project || '', }; Our state object has two properties, each corresponding to an input field that TimerForm manages. We set the initial state of these properties to the values passed down via props. If TimerForm is creating a new timer as opposed to editing an existing one, those props would be undefined. In that case, we initialize both to a blank string (''). We want to avoid initializing title or project to undefined. That’s because the value of an input field can’t technically ever be undefined. If it’s empty, its value in JavaScript is a blank string. In fact, if you initialize the value of an input field to undefined, React will complain. defaultValue only sets the value of the input field for the initial render. Instead of using defaultValue, we can connect our input fields directly to our component’s state using value. We could do something like this:
With this change, our input fields would be driven by state. Whenever the state properties title or project change, our input fields would be updated to reflect the new value. 90 Components However, this misses a key ingredient: We don’t currently have any way for the user to modify this state. The input field will start off in-sync with the component’s state. But the moment the user makes a modification, the input field will become out-of-sync with the component’s state. We can fix this by using React’s onChange attribute for input elements. Like onClick for button or a elements, we can set onChange to a function. Whenever the input field is changed, React will invoke the function specified. Let’s set the onChange attributes on both input fields to functions we’ll define next: time_tracking_app/public/js/app-2.js
The functions handleTitleChange and handleProjectChange will both modify their respective properties in state. Here’s what they look like: time_tracking_app/public/js/app-2.js handleTitleChange = (e) => { this.setState({ title: e.target.value }); }; handleProjectChange = (e) => { this.setState({ project: e.target.value }); }; When React invokes the function passed to onChange, it invokes the function with an event object. We call this argument e. The event object includes the updated value of the field under target.value. We update the state to the new value of the input field. Components 91 Using a combination of state, the value attribute, and the onChange attribute is the canonical method we use to write form elements in React. We explore forms in depth in the chapter “Forms.” We explore this topic specifically in the section “Uncontrolled vs. Controlled Components.” To recap, here’s an example of the lifecycle of TimerForm: 1. 2. 3. 4. 5. On the page is a timer with the title “Mow the lawn.” The user toggles open the edit form for this timer, mounting TimerForm to the page. TimerForm initializes the state property title to the string "Mow the lawn". The user modifies the input field, changing it to the value "Cut the grass". With every keystroke, React invokes handleTitleChange. The internal state of title is kept in-sync with what the user sees on the page. With TimerForm refactored, we’ve finished establishing our stateful data inside our elected components. Our downward data pipeline, props, is assembled. We’re ready — and perhaps a bit eager — to build out interactivity using inverse data flow. But before we do, let’s save and reload the app to ensure everything is working. We expect to see new example timers based on the hard-coded data in TimersDashboard. We also expect clicking the “+” button toggles open a form: Step 6: Add inverse data flow As we saw in the last chapter, children communicate with parents by calling functions that are handed to them via props. In the ProductHunt app, when an up-vote was clicked Product didn’t do any data management. It was not the owner of its state. Instead, it called a function given to it by ProductList, passing in its id. ProductList was then able to manage state accordingly. We are going to need inverse data flow in two areas: 92 Components • TimerForm needs to propagate create and update events (create while under ToggleableTimerForm and update while under EditableTimer). Both events will eventually reach TimersDashboard. • Timer has a fair amount of behavior. It needs to handle delete and edit clicks, as well as the start and stop timer logic. Let’s start with TimerForm. TimerForm To get a clear idea of what exactly TimerForm will require, we’ll start by adding event handlers to it and then work our way backwards up the hierarchy. TimerForm needs two event handlers: • When the form is submitted (creating or updating a timer) • When the “Cancel” button is clicked (closing the form) TimerForm will receive two functions as props to handle each event. The parent component that uses TimerForm is responsible for providing these functions: • props.onFormSubmit(): called when the form is submitted • props.onFormClose(): called when the “Cancel” button is clicked As we’ll see soon, this empowers the parent component to dictate what the behavior should be when these events occur. Let’s first modify the buttons on TimerForm. We’ll specify onClick attributes for each: time_tracking_app/public/js/app-3.js
Components 93 The onClick attribute for the “Submit” button specifies the function this.handleSubmit, which we’ll define next. The onClick attribute for the “Cancel” button specifies the prop onFormClose directly. Let’s see what handleSubmit looks like: time_tracking_app/public/js/app-3.js handleSubmit = () => { this.props.onFormSubmit({ id: this.props.id, title: this.state.title, project: this.state.project, }); }; render() { handleSubmit() calls a yet-to-be-defined function, onFormSubmit(). It passes in a data object with id, title, and project attributes. This means id will be undefined for creates, as no id exists yet. Before moving on, let’s make one last tweak to TimerForm: time_tracking_app/public/js/app-3.js render() { const submitText = this.props.id ? 'Update' : 'Create'; We have submitText switch on id as opposed to title. Using the id property to determine whether or not an object has been created is a more common practice. ToggleableTimerForm Let’s chase the submit event from TimerForm as it bubbles up the component hierarchy. First, we’ll modify ToggleableTimerForm. We need it to pass down two prop-functions to TimerForm, onFormClose() and onFormSubmit(): 94 Components time_tracking_app/public/js/app-3.js // Inside ToggleableTimerForm handleFormOpen = () => { this.setState({ isOpen: true }); }; handleFormClose = () => { this.setState({ isOpen: false }); }; handleFormSubmit = (timer) => { this.props.onFormSubmit(timer); this.setState({ isOpen: false }); }; render() { if (this.state.isOpen) { return ( ); } else { Looking first at the render() function, we can see we pass in the two functions as props. Functions are just like any other prop. Of most interest here is handleFormSubmit(). Remember, ToggleableTimerForm is not the manager of timer state. TimerForm has an event it’s emitting, in this case the submission of a new timer. ToggleableTimerForm is just a proxy of this message. So, when the form is submitted, it calls its own prop-function props.onFormSubmit(). We’ll eventually define this function in TimersDashboard. handleFormSubmit() accepts the argument timer. Recall that in TimerForm this argument is an object containing the desired timer properties. We just pass that argument along here. After invoking onFormSubmit(), handleFormSubmit() calls setState() to close its form. Note that the result of onFormSubmit() will not impact whether or not the form is closed. We invoke onFormSubmit(), which may eventually create an asynchronous call to a server. Execution will continue before we hear back from the server which means setState() will be called. If onFormSubmit() fails — such as if the server is temporarily unreachable — we’d ideally have some way to display an error message and re-open the form. Components 95 TimersDashboard We’ve reached the top of the hierarchy, TimersDashboard. As this component will be responsible for the data for the timers, it is here that we will define the logic for handling the events we’re capturing down at the leaf components. The first event we’re concerned with is the submission of a form. When this happens, either a new timer is being created or an existing one is being updated. We’ll use two separate functions to handle the two distinct events: • handleCreateFormSubmit() will handle creates and will be the function passed to ToggleableTimerForm • handleEditFormSubmit() will handle updates and will be the function passed to EditableTimerList Both functions travel down their respective component hierarchies until they reach TimerForm as the prop onFormSubmit(). Let’s start with handleCreateFormSubmit, which inserts a new timer into our timer list state: time_tracking_app/public/js/app-3.js // Inside TimersDashboard handleCreateFormSubmit = (timer) => { this.createTimer(timer); }; createTimer = (timer) => { const t = helpers.newTimer(timer); this.setState({ timers: this.state.timers.concat(t), }); }; render() { return (
96 Components
); } We create the timer object with helpers.newTimer(). You can peek at the implementation inside of helpers.js. We pass in the object that originated down in TimerForm. This object has title and project properties. helpers.newTimer() returns an object with those title and project properties as well as a generated id. The next line calls setState(), appending the new timer to our array of timers held under timers. We pass the whole state object to setState(). You might wonder: why separate handleCreateFormSubmit() and createTimer()? While not strictly required, the idea here is that we have one function for handling the event (handleCreateFormSubmit()) and another for performing the operation of creating a timer (createTimer()). This separation follows from the Single Responsibility Principle and enables us to call createTimer() from elsewhere if needed. We’ve finished wiring up the create timer flow from the form down in TimerForm up to the state managed in TimersDashboard. Save app.js and reload your browser. Toggle open the create form and create some new timers: Components 97 Updating timers We need to give the same treatment to the update timer flow. However, as you can see in the current state of the app, we haven’t yet added the ability for a timer to be edited. So we don’t have a way to display an edit form, which will be a prerequisite to submitting one. To display an edit form, the user clicks on the edit icon on a Timer. This should propagate an event up to EditableTimer and tell it to flip its child component, opening the form. Adding editability to Timer To notify our app that the user wants to edit a timer we need to add an onClick attribute to the span tag of the edit button. We anticipate a prop-function, onEditClick(): 98 Components time_tracking_app/public/js/app-4.js {/* Inside Timer.render() */}
Updating EditableTimer Now we’re prepared to update EditableTimer. Again, it will display either the TimerForm (if we’re editing) or an individual Timer (if we’re not editing). Let’s add event handlers for both possible child components. For TimerForm, we want to handle the form being closed or submitted. For Timer, we want to handle the edit icon being pressed: time_tracking_app/public/js/app-4.js // Inside EditableTimer handleEditClick = () => { this.openForm(); }; handleFormClose = () => { this.closeForm(); }; handleSubmit = (timer) => { this.props.onFormSubmit(timer); this.closeForm(); }; closeForm = () => { this.setState({ editFormOpen: false }); }; Components 99 openForm = () => { this.setState({ editFormOpen: true }); }; We pass these event handlers down as props: time_tracking_app/public/js/app-4.js render() { if (this.state.editFormOpen) { return ( ); } else { return ( ); } } Look a bit familiar? EditableTimer handles the same events emitted from TimerForm in a very similar manner as ToggleableTimerForm. This makes sense. Both EditableTimer and ToggleableTimerForm are just intermediaries between TimerForm and TimersDashboard. TimersDashboard is the one that defines the submit function handlers and assigns them to a given component tree. Like ToggleableTimerForm, EditableTimer doesn’t do anything with the incoming timer. In handleSubmit(), it just blindly passes this object along to its prop-function onFormSubmit(). It then closes the form with closeForm(). We pass along a new prop to Timer, onEditClick. The behavior for this function is defined in handleEditClick, which modifies the state for EditableTimer, opening the form. Components 100 Updating EditableTimerList Moving up a level, we make a one-line addition to EditableTimerList to send the submit function from TimersDashboard to each EditableTimer: time_tracking_app/public/js/app-4.js // Inside EditableTimerList const timers = this.props.timers.map((timer) => ( )); // ... EditableTimerList doesn’t need to do anything with this event so again we just pass the function on directly. Defining onEditFormSubmit() in TimersDashboard Last step with this pipeline is to define and pass down the submit function for edit forms in TimersDashboard. For creates, we have a function that creates a new timer object with the specified attributes and we append this new object to the end of the timers array in the state. For updates, we need to hunt through the timers array until we find the timer object that is being updated. As mentioned in the last chapter, the state object cannot be updated directly. We have to use setState(). Therefore, we’ll use map() to traverse the array of timer objects. If the timer’s id matches that of the form submitted, we’ll return a new object that contains the timer with the updated attributes. Otherwise we’ll just return the original timer. This new array of timer objects will be passed to setState(): 101 Components time_tracking_app/public/js/app-4.js // Inside TimersDashboard handleEditFormSubmit = (attrs) => { this.updateTimer(attrs); }; createTimer = (timer) => { const t = helpers.newTimer(timer); this.setState({ timers: this.state.timers.concat(t), }); }; updateTimer = (attrs) => { this.setState({ timers: this.state.timers.map((timer) => { if (timer.id === attrs.id) { return Object.assign({}, timer, { title: attrs.title, project: attrs.project, }); } else { return timer; } }), }); }; We pass this down as a prop inside render(): time_tracking_app/public/js/app-4.js { /* Inside TimersDashboard.render() */} Note that we can call map() on this.state.timers from within the JavaScript object we’re passing to setState(). This is an often used pattern. The call is evaluated and then the property timers is set to the result. 102 Components Inside of the map() function we check if the timer matches the one being updated. If not, we just return the timer. Otherwise, we use Object#assign() to return a new object with the timer’s updated attributes. Remember, it’s important here that we treat state as immutable. By creating a new timers object and then using Object#assign() to populate it, we’re not modifying any of the objects sitting in state. We discuss the Object#assign() method in the last chapter. As we did with ToggleableTimerForm and handleCreateFormSubmit, we pass down handleEditFormSubmit as the prop onFormSubmit. TimerForm calls this prop, oblivious to the fact that this function is entirely different when it is rendered underneath EditableTimer as opposed to ToggleableTimerForm. Both of the forms are wired up! Save app.js, reload the page, and try both creating and updating timers. You can also click “Cancel” on an open form to close it: The rest of our work resides within the timer. We need to: • Wire up the trash button (deleting a timer) • Implement the start/stop buttons and the timing logic itself At that point, we’ll have a complete server-less solution. 103 Components Try it yourself: Before moving on to the next section, see how far you can get wiring up the trash button by yourself. Move ahead afterwards and verify your solution is sound. Deleting timers Adding the event handler to Timer In Timer, we define a function to handle trash button click events: time_tracking_app/public/js/app-5.js class Timer extends React.Component { handleTrashClick = () => { this.props.onTrashClick(this.props.id); }; render() { And then use onClick to connect that function to the trash icon: time_tracking_app/public/js/app-5.js {/* Inside Timer.render() */}
We’ve yet to define the function that will be set as the prop onTrashClick(). But you can imagine that when this event reaches the top (TimersDashboard), we’re going to need the id to sort out which timer is being deleted. handleTrashClick() provides the id to this function. Components Routing through EditableTimer EditableTimer just proxies the function: time_tracking_app/public/js/app-5.js // Inside EditableTimer } else { return ( ); } Routing through EditableTimerList As does EditableTimerList: time_tracking_app/public/js/app-5.js // Inside EditableTimerList.render() const timers = this.props.timers.map((timer) => ( )); 104 105 Components Implementing the delete function in TimersDashboard The last step is to define the function in TimersDashboard that deletes the desired timer from the state array. There are many ways to accomplish this in JavaScript. Don’t sweat it if your solution was not the same or if you didn’t quite work one out. We add our handler function that we ultimately pass down as a prop: time_tracking_app/public/js/app-5.js // Inside TimersDashboard handleEditFormSubmit = (attrs) => { this.updateTimer(attrs); }; handleTrashClick = (timerId) => { this.deleteTimer(timerId); }; deleteTimer() uses Array’s filter() method to return a new array with the timer object that has an id matching timerId removed: time_tracking_app/public/js/app-5.js // Inside TimersDashboard deleteTimer = (timerId) => { this.setState({ timers: this.state.timers.filter(t => t.id !== timerId), }); }; Finally, we pass down handleTrashClick() as a prop: time_tracking_app/public/js/app-5.js {/* Inside TimersDashboard.render() */} 106 Components Array’s filter() method accepts a function that is used to “test” each element in the array. It returns a new array containing all the elements that “passed” the test. If the function returns true, the element is kept. Save app.js and reload the app. Low and behold, you can delete timers: Adding timing functionality Create, update, and delete (CRUD) capability is now in place for our timers. The next challenge: making these timers functional. There are several different ways we can implement a timer system. The simplest approach would be to have a function update the elapsed property on each timer every second. But this is severely limited. What happens when the app is closed? The timer should continue “running.” This is why we’ve included the timer property runningSince. A timer is initialized with elapsed equal to 0. When a user clicks “Start”, we do not increment elapsed. Instead, we just set runningSince to the start time. We can then use the difference between the start time and the current time to render the time for the user. When the user clicks “Stop”, the difference between the start time and the current time is added to elapsed. runningSince is set to null. Therefore, at any given time, we can derive how long the timer has been running by taking Date.now() - runningSince and adding it to the total accumulated time (elapsed). We’ll calculate this inside the Timer component. Components 107 For the app to truly feel like a running timer, we want React to constantly perform this operation and re-render the timers. But elapsed and runningSince will not be changing while the timer is running. So the one mechanism we’ve seen so far to trigger a render() call will not be sufficient. Instead, we can use React’s forceUpdate() method. This forces a React component to re-render. We can call it on an interval to yield the smooth appearance of a live timer. Adding a forceUpdate() interval to Timer helpers.renderElapsedString() accepts an optional second argument, runningSince. It will add the delta of Date.now() - runningSince to elapsed and use the function millisecondsToHuman() to return a string formatted as HH:MM:SS. We will establish an interval to run forceUpdate() after the component mounts: time_tracking_app/public/js/app-6.js class Timer extends React.Component { componentDidMount() { this.forceUpdateInterval = setInterval(() => this.forceUpdate(), 50); } componentWillUnmount() { clearInterval(this.forceUpdateInterval); } handleTrashClick = () => { this.props.onTrashClick(this.props.id); }; render() { const elapsedString = helpers.renderElapsedString( this.props.elapsed, this.props.runningSince ); return ( In componentDidMount(), we use the JavaScript function setInterval(). This will invoke the function forceUpdate() once every 50 ms, causing the component to re-render. We set the return of setInterval() to this.forceUpdateInterval. In componentWillUnmount(), we use clearInterval() to stop the interval this.forceUpdateInterval. componentWillUnmount() is called before a component is removed from the app. This will happen if a timer is deleted. We want to ensure we do not continue calling forceUpdate() after the timer has been removed from the page. React will throw errors. 108 Components setInterval() accepts two arguments. The first is the function you would like to call repeatedly. The second is the interval on which to call that function (in milliseconds). setInterval() returns a unique interval ID. You can pass this interval ID to clearInterval() at any time to halt the interval. You might ask: Wouldn’t it be more efficient if we did not continuously call forceUpdate() on timers that are not running? Indeed, we would save a few cycles. But it would not be worth the added code complexity. React will call render() which performs some inexpensive operations in JavaScript. It will then compare this result to the previous call to render() and see that nothing has changed. It stops there — it won’t attempt any DOM manipulation. The 50 ms interval was not derived scientifically. Selecting an interval that’s too high will make the timer look unnatural. It would jump unevenly between values. Selecting an interval that’s too low would just be an unnecessary amount of work. A 50 ms interval looks good to humans and is ages in computerland. Try it out Save app.js and reload. The first timer should be running. We’ve begun to carve out the app’s real utility! We need only wire up the start/stop button and our server-less app will be feature complete. Add start and stop functionality The action button at the bottom of each timer should display “Start” if the timer is paused and “Stop” if the timer is running. It should also propagate events when clicked, depending on if the timer is being stopped or started. We could build all of this functionality into Timer. We could have Timer decide to render one HTML snippet or another depending on if it is running. But that would be adding more responsibility and complexity to Timer. Instead, let’s make the button its own React component. Add timer action events to Timer Let’s modify Timer, anticipating a new component called TimerActionButton. This button just needs to know if the timer is running. It also needs to be able to propagate two events, onStartClick() and 109 Components onStopClick(). These events will eventually need to make it all the way up to TimersDashboard, which can modify runningSince on the timer. First, the event handlers: time_tracking_app/public/js/app-7.js // Inside Timer componentWillUnmount() { clearInterval(this.forceUpdateInterval); } handleStartClick = () => { this.props.onStartClick(this.props.id); }; handleStopClick = () => { this.props.onStopClick(this.props.id); }; // ... Then, inside render(), we’ll declare TimerActionButton at the bottom of the outermost div: time_tracking_app/public/js/app-7.js {/* At the bottom of `Timer.render()`` */}
); We use the same technique used in other click-handlers: onClick on the HTML element specifies a handler function in the component that invokes a prop-function, passing in the timer’s id. We use !! here to derive the boolean prop timerIsRunning for TimerActionButton. !! returns false when runningSince is null. Create TimerActionButton Create the TimerActionButton component now: Components 110 time_tracking_app/public/js/app-7.js class TimerActionButton extends React.Component { render() { if (this.props.timerIsRunning) { return (
Stop
); } else { return (
Start
); } } } We render one HTML snippet or another based on this.props.timerIsRunning. You know the drill. Now we run these events up the component hierarchy, all the way up to TimersDashboard where we’re managing state: Run the events through EditableTimer and EditableTimerList First EditableTimer: Components 111 time_tracking_app/public/js/app-7.js // Inside EditableTimer } else { return ( ); } And then EditableTimerList: time_tracking_app/public/js/app-7.js // Inside EditableTimerList const timers = this.props.timers.map((timer) => ( )); Finally, we define these functions in TimersDashboard. They should hunt through the state timers array using map, setting runningSince appropriately when they find the matching timer. First we define the handling functions: Components time_tracking_app/public/js/app-7.js // Inside TimersDashboard handleTrashClick = (timerId) => { this.deleteTimer(timerId); }; handleStartClick = (timerId) => { this.startTimer(timerId); }; handleStopClick = (timerId) => { this.stopTimer(timerId); }; And then startTimer() and stopTimer(): time_tracking_app/public/js/app-7.js deleteTimer = (timerId) => { this.setState({ timers: this.state.timers.filter(t => t.id !== timerId), }); }; startTimer = (timerId) => { const now = Date.now(); this.setState({ timers: this.state.timers.map((timer) => { if (timer.id === timerId) { return Object.assign({}, timer, { runningSince: now, }); } else { return timer; } }), }); }; stopTimer = (timerId) => { const now = Date.now(); 112 113 Components this.setState({ timers: this.state.timers.map((timer) => { if (timer.id === timerId) { const lastElapsed = now - timer.runningSince; return Object.assign({}, timer, { elapsed: timer.elapsed + lastElapsed, runningSince: null, }); } else { return timer; } }), }); }; Finally, we pass them down as props: time_tracking_app/public/js/app-7.js {/* Inside TimerDashboard.render() */} When startTimer comes across the relevant timer within its map call, it sets the property runningSince to the current time. stopTimer calculates lastElapsed, the amount of time that the timer has been running for since it was started. It adds this amount to elapsed and sets runningSince to null, “stopping” the timer. Try it out Save app.js, reload, and behold! You can now create, update, and delete timers as well as actually use them to time things: Components 114 This is excellent progress. But, without a connection to a server, our app is ephemeral. If we refresh the page, we lose all of our timer data. Our app does not have any persistence. A server can give us persistence. We’ll have our server write all changes to timer data to a file. Instead of hard-coding state inside of the TimersDashboard component, when our app loads it will query the server and construct its timer state based on the data the server provides. We’ll then have our React app notify the server about any state changes, like when a timer is started. Communicating with a server is the last big major building block you’ll need to develop and distribute real-world web applications with React. Methodology review While building our time-logging app, we learned and applied a methodology for building React apps. Again, those steps were: 1. Break the app into components We mapped out the component structure of our app by examining the app’s working UI. We then applied the single-responsibility principle to break components down so that each had minimal viable functionality. 2. Build a static version of the app Our bottom-level (user-visible) components rendered HTML based on static props, passed down from parents. 3. Determine what should be stateful We used a series of questions to deduce what data should be stateful. This data was represented in our static app as props. 4. Determine in which component each piece of state should live We used another series of questions to determine which component should own each piece of state. TimersDashboard owned timer state data and ToggleableTimerForm and EditableTimer both held state pertaining to whether or not to render a TimerForm. Components 115 5. Hard-code initial states We then initialized state-owners’ state properties with hard-coded values. 6. Add inverse data flow We added interactivity by decorating buttons with onClick handlers. These called functions that were passed in as props down the hierarchy from whichever component owned the relevant state being manipulated. The final step is 7. Add server communication. We’ll tackle this in the next chapter. Components & Servers Introduction In the last chapter, we used a methodology to construct a React app. State management of timers takes place in the top-level component TimersDashboard. As in all React apps, data flows from the top down through the component tree to leaf components. Leaf components communicate events to state managers by calling prop-functions. At the moment, TimersDashboard has a hard-coded initial state. Any mutations to the state will only live as long as the browser window is open. That’s because all state changes are happening in-memory inside of React. We need our React app to communicate with a server. The server will be in charge of persisting the data. In this app, data persistence happens inside of a file, data.json. EditableTimer and ToggleableTimerForm also have hard-coded initial state. But because this state is just whether or not their forms are open, we don’t need to communicate these state changes to the server. We’re OK with the forms starting off closed every time the app boots. Preparation To help you get familiar with the API for this project and working with APIs in general, we have a short section where we make requests to the API outside of React. curl We’ll use a tool called curl to make more involved requests from the command line. OS X users should already have curl installed. Windows users can download and install curl here: https://curl.haxx.se/download.html38 . server.js Included in the root of your project folder is a file called server.js. This is a Node.js server specifically designed for our time-tracking app. You don’t have to know anything about Node.js or about servers in general to work with the server we’ve supplied. We’ll provide the guidance that you need. 38 https://curl.haxx.se/download.html 117 Components & Servers server.js uses the file data.json as its “store.” The server will read and write to this file to persist data. You can take a look at that file to see the initial state of the store that we’ve provided. server.js will return the contents of data.json when asked for all items. When notified, the server will reflect any updates, deletes, or timer stops and starts in data.json. This is how data will be persisted even if the browser is reloaded or closed. Before we start working with the server, let’s briefly cover its API. Again, don’t be concerned if this outline is a bit perplexing. It will hopefully become clearer as we start writing some code. The Server API Our ultimate goal in this chapter is to replicate state changes on the server. We’re not going to move all state management exclusively to the server. Instead, the server will maintain its state (in data.json) and React will maintain its state (in this case, within this.state in TimersDashboard). We’ll demonstrate later why keeping state in both places is desirable. TimersDashboard communicates with the server If we perform an operation on the React (“client”) state that we want to be persisted, then we also need to notify the server of that state change. This will keep the two states in sync. We’ll consider these our “write” operations. The write operations we want to send to the server are: • A timer is created Components & Servers • • • • 118 A timer is updated A timer is deleted A timer is started A timer is stopped We’ll have just one read operation: requesting all of the timers from the server. HTTP APIs This section assumes a little familiarity with HTTP APIs. If you’re not familiar with HTTP APIs, you may want to read up on them39 at some point. However, don’t be deterred from continuing with this chapter for the time being. Essentially what we’re doing is making a “call” from our browser out to a local server and conforming to a specified format. text/html endpoint GET / This entire time, server.js has actually been responsible for serving the app. When your browser requests localhost:3000/, the server returns the file index.html. index.html loads in all of our JavaScript/React code. Note that React never makes a request to the server at this path. This is just used by the browser to load the app. React only communicates with the JSON endpoints. JSON endpoints data.json is a JSON document. As touched on in the last chapter, JSON is a format for storing human-readable data objects. We can serialize JavaScript objects into JSON. This enables JavaScript objects to be stored in text files and transported over the network. data.json contains an array of objects. While not strictly JavaScript, the data in this array can be readily loaded into JavaScript. In server.js, we see lines like this: 39 http://www.andrewhavens.com/posts/20/beginners-guide-to-creating-a-rest-api/ Components & Servers 119 fs.readFile(DATA_FILE, function(err, data) { const timers = JSON.parse(data); // ... }); data is a string, the JSON. JSON.parse() converts this string into an actual JavaScript array of objects. GET /api/timers Returns a list of all timers. POST /api/timers Accepts a JSON body with title, project, and id attributes. Will insert a new timer object into its store. POST /api/timers/start Accepts a JSON body with the attribute id and start (a timestamp). Hunts through its store and finds the timer with the matching id. Sets its runningSince to start. POST /api/timers/stop Accepts a JSON body with the attribute id and stop (a timestamp). Hunts through its store and finds the timer with the matching id. Updates elapsed according to how long the timer has been running (stop - runningSince). Sets runningSince to null. PUT /api/timers Accepts a JSON body with the attributes id and title and/or project. Hunts through its store and finds the timer with the matching id. Updates title and/or project to new attributes. DELETE /api/timers Accepts a JSON body with the attribute id. Hunts through its store and deletes the timer with the matching id. Playing with the API If your server is not booted, make sure to boot it: npm start You can visit the endpoint /api/timers endpoint in your browser and see the JSON response (localhost:3000/api/timers). When you visit a new URL in your browser, your browser makes a GET request. So our browser calls GET /api/timers and the server returns all of the timers: 120 Components & Servers Note that the server stripped all of the extraneous whitespace in data.json, including newlines, to keep the payload as small as possible. Those only exist in data.json to make it human-readable. We can use a Chrome extension like JSONView40 to “humanize” the raw JSON. JSONView takes these raw JSON chunks and adds back in the whitespace for readability: Visiting the endpoint after installing JSONView We can only easily use the browser to make GET requests. For writing data — like starting and stopping timers — we’ll have to make POST, PUT, or DELETE requests. We’ll use curl to play around with writing data. Run the following command from the command line: 40 https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc Components & Servers 121 $ curl -X GET localhost:3000/api/timers The -X flag specifies which HTTP method to use. It should return a response that looks a bit like this: [{"title":"Mow the lawn","project":"House Chores","elapsed":5456099,"id":"0a4a79\ cb-b06d-4cb1-883d-549a1e3b66d7"},{"title":"Clear paper jam","project":"Office Ch\ ores","elapsed":1273998,"id":"a73c1d19-f32d-4aff-b470-cea4e792406a"},{"title":"P\ onder origins of universe","project":"Life Chores","id":"2c43306e-5b44-4ff8-8753\ -33c35adbd06f","elapsed":11750,"runningSince":"1456225941911"}] You can start one of the timers by issuing a PUT request to the /api/timers/start endpoint. We need to send along the id of one of the timers and a start timestamp: $ curl -X POST \ -H 'Content-Type: application/json' \ -d '{"start":1456468632194,"id":"a73c1d19-f32d-4aff-b470-cea4e792406a"}' \ localhost:3000/api/timers/start The -H flag sets a header for our HTTP request, Content-Type. We’re informing the server that the body of the request is JSON. The -d flag sets the body of our request. Inside of single-quotes '' is the JSON data. When you press enter, curl will quickly return without any output. The server doesn’t return anything on success for this endpoint. If you open up data.json, you will see that the timer you specified now has a runningSince property, set to the value we specified as start in our request. If you’d like, you can play around with the other endpoints to get a feel for how they work. Just be sure to set the appropriate method with -X and to pass along the JSON Content-Type for the write endpoints. We’ve written a small library, client, to aid you in interfacing with the API in JavaScript. Note that the backslash \ above is only used to break the command out over multiple lines for readability. This only works on macOS and Linux. Windows users can just type it out as one long string. Tool tip: jq macOS and Linux users: If you want to parse and process JSON on the command line, we highly recommend the tool “jq.” You can pipe curl responses directly into jq to have the response pretty-formatted: Components & Servers 122 curl -X GET localhost:3000/api/timers | jq '.' You can also do some powerful manipulation of JSON, like iterating over all objects in the response and returning a particular field. In this example, we extract just the id property of every object in an array: curl -X GET localhost:3000/api/timers | jq '.[] | { id }' You can download jq here: https://stedolan.github.io/jq/a . a https://stedolan.github.io/jq/ Loading state from the server Right now, we set initial state in TimersDashboard by hardcoding a JavaScript object, an array of timers. Let’s modify this function to load data from the server instead. We’ve written the client library that your React app will use to interact with the server, client. The library is defined in public/js/client.js. We’ll use it first and then take a look at how it works in the next section. The GET /api/timers endpoint provides a list of all timers, as represented in data.json. We can use client.getTimers() to call this endpoint from our React app. We’ll do this to “hydrate” the state kept by TimersDashboard. When we call client.getTimers(), the network request is made asynchronously. The function call itself is not going to return anything useful: // Wrong // `getTimers()` does not return the list of timers const timers = client.getTimers(); Instead, we can pass getTimers() a success function. getTimers() will invoke that function after it hears back from the server if the server successfully returned a result. getTimers() will invoke the function with a single argument, the list of timers returned by the server: Components & Servers 123 // Passing `getTimers()` a success function client.getTimers((serverTimers) => ( // do something with the array of timers, `serverTimers` )); client.getTimers() uses the Fetch API, which we cover in the next section. For our purposes, the important thing to know is that when getTimers() is invoked, it fires off the request to the server and then returns control flow immediately. The execution of our program does not wait for the server’s response. This is why getTimers() is called an asynchronous function. The success function we pass to getTimers() is called a callback. We’re saying: “When you finally hear back from the server, if it’s a successful response, invoke this function.” This asynchronous paradigm ensures that execution of our JavaScript is not blocked by I/O. We’ll initialize our component’s state with the timers property set to a blank array. This will allow all components to mount and perform their initial render. Then, we can populate the app by making a request to the server and setting the state: time_tracking_app/public/js/app-8.js class TimersDashboard extends React.Component { state = { timers: [], }; componentDidMount() { this.loadTimersFromServer(); setInterval(this.loadTimersFromServer, 5000); } loadTimersFromServer = () => { client.getTimers((serverTimers) => ( this.setState({ timers: serverTimers }) ) ); }; // ... A timeline is the best medium for illustrating what happens: Components & Servers 124 1. Before initial render React initializes the component. state is set to an object with the property timers, a blank array, is returned. 2. The initial render React then calls render() on TimersDashboard. In order for the render to complete, EditableTimerList and ToggleableTimerForm — its two children — must be rendered. 3. Children are rendered EditableTimerList has its render method called. Because it was passed a blank data array, it simply produces the following HTML output:
ToggleableTimerForm renders its HTML, which is the “+” button. 4. Initial render is finished With its children rendered, the initial render of TimersDashboard is finished and the HTML is written to the DOM. 5. componentDidMount is invoked Now that the component is mounted, componentDidMount() is called on TimersDashboard. This method calls loadTimersFromServer(). In turn, that function calls client.getTimers(). That will make the HTTP request to our server, requesting the list of timers. When client hears back, it invokes our success function. On invocation, the success function is passed one argument, serverTimers. This is the array of timers returned by the server. We then call setState(), which will trigger a new render. The new render populates our app with EditableTimer children and all of their children. The app is fully loaded and at an imperceptibly fast speed for the end user. We also do one other interesting thing in componentDidMount. We use setInterval() to ensure loadTimersFromServer() is called every 5 seconds. While we will be doing our best to mirror state changes between client and server, this hard-refresh of state from the server will ensure our client will always be correct should it shift from the server. The server is considered the master holder of state. Our client is a mere replica. This becomes incredibly powerful in a multi-instance scenario. If you have two instances of your app running — in two different tabs or two different computers — changes in one will be pushed to the other within five seconds. Components & Servers 125 Try it out Let’s have fun with this now. Save app.js and reload the app. You should see a whole new list of timers, driven by data.json. Any action you take will be wiped out within five seconds. Every five seconds, state is restored from the server. For instance, try deleting a timer and witness it resiliently spring back unscathed. Because we’re not telling the server about these actions, its state remains unchanged. On the flip-side, you can try modifying data.json. Notice how any modifications to data.json will be propagated to your app in under five seconds. Neat. We’re loading the initial state from the server. We have an interval function in place to ensure the client app’s state does not drift from the server’s in a multi-instance scenario. We’ll need to inform our server of the rest of our state changes: creates, updates (including starts and stops), and deletes. But first, let’s pop open the logic behind client to see how it works. While it is indeed neat that changes to our server data is seamlessly propagated to our view, in certain applications — like messaging — five seconds is almost an eternity. We’ll cover the concept of long-polling in a future app. Long-polling enables changes to be pushed to clients near instantly. client If you open up client.js, the first method defined in the library is getTimers(): time_tracking_app/public/js/client.js function getTimers(success) { return fetch('/api/timers', { headers: { Accept: 'application/json', }, }).then(checkStatus) .then(parseJSON) .then(success); } We are using the new Fetch API to perform all of our HTTP requests. Fetch’s interface should look relatively familiar if you’ve ever used XMLHttpRequest or jQuery’s ajax(). Components & Servers 126 Fetch Until Fetch, JavaScript developers had two options for making web requests: Use XMLHttpRequest which is supported natively in all browsers or import a library that provides a wrapper around it (like jQuery’s ajax()). Fetch provides a better interface than XMLHttpRequest. And while Fetch is still undergoing standardization, it is already supported by a few major browsers. At the time of writing, Fetch is turned on by default in Firefox 39 and above and Chrome 42 and above. Until Fetch is more widely adopted by browsers, it’s a good idea to include the library just in case. We’ve already done so inside index.html: As we can see in client.getTimers(), fetch() accepts two arguments: • The path to the resource we want to fetch • An object of request parameters By default, Fetch makes a GET request, so we’re telling Fetch to make a GET request to /api/timers. We also pass along one parameter: headers, the HTTP headers in our request. We’re telling the server we’ll accept only a JSON response. Attached to the end of our call to fetch(), we have a chain of .then() statements: time_tracking_app/public/js/client.js }).then(checkStatus) .then(parseJSON) .then(success); To understand how this works, let’s first review the functions that we pass to each .then() statement: • checkStatus(): This function is defined inside of client.js. It checks if the server returned an error. If the server returned an error, checkStatus() logs the error to the console. • parseJSON(): This function is also defined inside of client.js. It takes the response object emitted by fetch() and returns a JavaScript object. • success(): This is the function we pass as an argument to getTimers(). getTimers() will invoke this function if the server successfully returned a response. Components & Servers 127 Fetch returns a promise. While we won’t go into detail about promises, as you can see here a promise allows you to chain .then() statements. We pass each .then() statement a function. What we’re essentially saying here is: “Fetching the timers from /api/timers then check the status code returned by the server. Then, extract the JavaScript object from the response. Then, pass that object to the success function.” At each stage of the pipeline, the result of the previous statement is passed as the argument to the next one: 1. 2. 3. 4. 5. When checkStatus() is invoked, it’s passed a Fetch response object that fetch() returns. checkStatus(), after verifying the response, returns the same response object. parseJSON() is invoked and passed the response object returned by checkStatus(). parseJSON() returns the JavaScript array of timers returned by the server. success() is invoked with the array of timers returned by parseJSON(). We could attach an infinite number of .then() statements to our pipeline. This pattern enables us to chain multiple function calls together in an easy-to-read format that supports asynchronous functions like fetch(). It’s OK if you’re still uncomfortable with the concept of promises. We’ve written all the client code for this chapter for you, so you won’t have trouble completing this chapter. You can come back afterwards to play around with client.js and get a feel for how it works. You can read more about JavaScript’s Fetch here41 and promises here42 . Looking at the rest of the functions in client.js, you’ll note the methods contain much of the same boilerplate with small differences based on the endpoint of the API we are calling. We just looked at getTimers() which demonstrates reading from the server. We’ll look at one more function, one that writes to the server. startTimer() makes a POST request to the /api/timers/start endpoint. The server needs the id of the timer and the start time. That request method looks like: 41 42 https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise Components & Servers 128 time_tracking_app/public/js/client.js function startTimer(data) { return fetch('/api/timers/start', { method: 'post', body: JSON.stringify(data), headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, }).then(checkStatus); } In addition to headers, the request parameters object that we pass to fetch() has two more properties: time_tracking_app/public/js/client.js method: 'post', body: JSON.stringify(data), Those are: • method: The HTTP request method. fetch() defaults to a GET request, so we specify we’d like a POST here. • body: The body of our HTTP request, the data we’re sending to the server. startTimer() expects an argument, data. This is the object that will be sent along in the body of our request. It contains the properties id and start. An invocation of startTimer() might look like this: // Example invocation of `startTimer()` startTimer( { id: "bc5ea63b-9a21-4233-8a76-f4bca9d0a042", start: 1455584369113, } ); In this example, the body of our request to the server will look like this: Components & Servers 129 { "id": "bc5ea63b-9a21-4233-8a76-f4bca9d0a042", "start": 1455584369113 } The server will extract the id and start timestamp from the body and “start” the timer. We don’t pass startTimers() a success function. Our app does not need data from the server for this request and indeed our server will not return anything besides an “OK” anyway. getTimers() is our only read operation and therefore the only one we’ll pass a success function. The rest of our calls to the server are writes. Let’s implement those now. Sending starts and stops to the server We can use the methods startTimer() and stopTimer() on client to make calls to the appropriate endpoints on the server. We just need to pass in an object that includes the id of the timer as well as the time it was started/stopped: time_tracking_app/public/js/app-9.js // Inside TimersDashboard // ... startTimer = (timerId) => { const now = Date.now(); this.setState({ timers: this.state.timers.map((timer) => { if (timer.id === timerId) { return Object.assign({}, timer, { runningSince: now, }); } else { return timer; } }), }); client.startTimer( { id: timerId, start: now } ); }; Components & Servers 130 stopTimer = (timerId) => { const now = Date.now(); this.setState({ timers: this.state.timers.map((timer) => { if (timer.id === timerId) { const lastElapsed = now - timer.runningSince; return Object.assign({}, timer, { elapsed: timer.elapsed + lastElapsed, runningSince: null, }); } else { return timer; } }), }); client.stopTimer( { id: timerId, stop: now } ); }; render() { You might ask: Why do we still manually make the state change within React? Can’t we just inform the server of the action taken and then update state based on the server, the source of truth? Indeed, the following implementation is valid: startTimer: function (timerId) { const now = Date.now(); client.startTimer( { id: timerId, start: now } ).then(loadTimersFromServer); }, We can chain a .then() to startTimer() as that function returns our original promise object. The last stage of the startTimer() pipeline would then be invoking the function loadTimersFromServer(). So immediately after the server processes our start timer request, we would make a subsequent request asking for the latest list of timers. This response would contain the now-running timer. React’s state updates and the running timer would then be reflected in the UI. Components & Servers 131 Again, this is valid. However, the user experience will leave something to be desired. Right now, clicking the start/stop button gives instantaneous feedback because the state changes locally and React immediately re-renders. If we waited to hear back from the server, there might be a noticeable delay between the action (mouse click) and the response (timer starts running). You can try it yourself locally, but the delay would be most noticeable if the request had to go out over the internet. What we’re doing here is called optimistic updating. We’re updating the client locally before waiting to hear from the server. This duplicates our state update efforts, as we perform updates on both the client and the server. But it makes our app as responsive as possible. The “optimism” we have here is that the request will succeed and not fail with an error. Using the same pattern as we did with starts and stops, see if you can implement creates, updates, and deletes on your own. Come back and compare your work with the next section. Optimistic updating: Validations Whenever we optimistic update, we always try to replicate whatever restrictions the server would have. This way, our client state changes under the same conditions as our server state. For example, imagine if our server enforced that a timer’s title cannot contain symbols. But the client did not enforce such a restriction. What would happen? A user has a timer named Gardening. He feels a bit cheeky and renames it Gardening :P. The UI immediately reflects his changes, displaying Gardening :P as the new name of the timer. Satisfied, the user is about to get up and grab his shears. But wait! His timer’s name suddenly snaps back to Gardening. To successfully pull off eager updating, we must diligently replicate the code that manages state changes on both the client and the server. Furthermore, in a production app we should surface any errors the request to the server returns in the event that there is an inconsistency in the code or a fluke (the server is down). Sending creates, updates, and deletes to the server Components & Servers 132 time_tracking_app/public/js/app-complete.js // Inside TimersDashboard // ... createTimer = (timer) => { const t = helpers.newTimer(timer); this.setState({ timers: this.state.timers.concat(t), }); client.createTimer(t); }; updateTimer = (attrs) => { this.setState({ timers: this.state.timers.map((timer) => { if (timer.id === attrs.id) { return Object.assign({}, timer, { title: attrs.title, project: attrs.project, }); } else { return timer; } }), }); client.updateTimer(attrs); }; deleteTimer = (timerId) => { this.setState({ timers: this.state.timers.filter(t => t.id !== timerId), }); client.deleteTimer( { id: timerId } ); }; startTimer = (timerId) => { Recall that, in createTimer() and updateTimer() respectively, the timer and attrs objects contain Components & Servers 133 an id property, as required by the server. For creates, we need to send a full timer object. It should have an id, a title, and a project. For updates, we can send an id along with just whatever attributes are being updated. Right now, we always send along title and project regardless of what has changed. But it’s worth noting this difference as it’s reflected in the variable names that we are using (timer vs attrs). Give it a spin We are now sending all of our state changes to the server. Save app.js and reload the app. Add some timers, start some timers, and refresh and note that everything is persisted. You can even make changes to your app in one browser tab and see the changes propagate to another tab. Next up We’ve worked through a reusable methodology for building React apps and now have an understanding of how we connect a React app to a web server. Armed with these concepts, you’re already equipped to build a variety of dynamic web applications. In imminent chapters, we’ll cover a variety of different component types that you encounter across the web (like forms and date pickers). We’ll also explore state management paradigms for more complex applications. JSX and the Virtual DOM React Uses a Virtual DOM React works differently than many earlier front-end JavaScript frameworks in that instead of working with the browser’s DOM, it builds a virtual representation of the DOM. By virtual, we mean a tree of JavaScript objects that represent the “actual DOM”. More on this in a minute. In React, we do not directly manipulate the actual DOM. Instead, we must manipulate the virtual representation and let React take care of changing the browser’s DOM. As we’ll see in this chapter, this is a very powerful feature but it requires us to think differently about how we build web apps. Why Not Modify the Actual DOM? It’s worth asking: why do we need a Virtual DOM? Can’t we just use the “actual-DOM”? When we do “classic-“ (e.g. jQuery-) style web development, we would typically: 1. locate an element (using document.querySelector or document.getElementById) and then 2. modify that element directly (say, by calling .innerHTML() on the element). This style of development is problematic in that: • It’s hard to keep track of changes - it can become difficult keep track of current (and prior) state of the DOM to manipulate it into the form we need • It can be slow - modifying the actual-DOM is a costly operation, and modifying the DOM on every change can cause poor performance What is a Virtual DOM? The Virtual DOM was created to deal with these issues. But what is the Virtual DOM anyway? The Virtual DOM is a tree of JavaScript objects that represents the actual DOM. One of the interesting reasons to use the Virtual DOM is the API it gives us. When using the Virtual DOM we code as if we’re recreating the entire DOM on every update. JSX and the Virtual DOM 135 This idea of re-creating the entire DOM results in an easy-to-comprehend development model: instead of the developer keeping track of all DOM state changes, the developer simply returns the DOM they wish to see. React takes care of the transformation behind the scenes. This idea of re-creating the Virtual DOM every update might sound like a bad idea: isn’t it going to be slow? In fact, React’s Virtual DOM implementation comes with important performance optimizations that make it very fast. The Virtual DOM will: • use efficient diffing algorithms, in order to know what changed • update subtrees of the DOM simultaneously • batch updates to the DOM All of this results in an easy-to-use and optimized way to build web apps. Virtual DOM Pieces Again, when building a web app in React, we’re not working directly with the browser’s “actual DOM” directly, but instead a virtual representation of it. Our job is to provide React with enough information to build a JavaScript object that represents what the browser will render. But what does this Virtual DOM JavaScript object actually consist of? React’s Virtual DOM is a tree of ReactElements. Understanding the Virtual DOM, ReactElements, and how they interact with the “actual DOM” is a lot easier to understand by working through some examples, which we’ll do below. Q: Virtual DOM vs. Shadow DOM, are they the same thing? (A: No) Maybe you’ve heard of the “Shadow DOM” and you’re wondering, is the Shadow DOM the same thing as the Virtual DOM? The answer is no. The Virtual DOM is a tree of JavaScript objects that represent the real DOM elements. The Shadow DOM is a form of encapsulation on our elements. Think about using the

Source Exif Data:
File Type                       : PDF
File Type Extension             : pdf
MIME Type                       : application/pdf
PDF Version                     : 1.5
Linearized                      : No
Modify Date                     : 2017:06:14 09:52:37-06:00
Create Date                     : 2017:06:14 15:25:34-00:00
Author                          : Anthony Accomazzo, Ari Lerner, David Guttman, Nate Murray, Clay Allsopp and Tyler McGinnis
Title                           : Fullstack React
Creator                         : LaTeX with hyperref package
Producer                        : XeTeX 0.99996
Page Count                      : 825
EXIF Metadata provided by
EXIF.tools

Navigation menu