-
Notifications
You must be signed in to change notification settings - Fork 101
/
index.html
620 lines (592 loc) · 63.4 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
<!doctype html>
<html>
<body>
<meta charset="UTF-8">
<style>
/*! https://github.com/MozMorris/tomorrow-pygments/blob/master/css/tomorrow.css */.highlight .gh,.highlight .gp,.highlight .gs,.highlight .gu{font-weight:700}.highlight .hll{background-color:#d6d6d6}.highlight{background:#fff;color:#4d4d4c}.highlight .c{color:#8e908c}.highlight .err{color:#c82829}.highlight .k{color:#8959a8}.highlight .l{color:#f5871f}.highlight .n{color:#4d4d4c}.highlight .o{color:#3e999f}.highlight .p{color:#4d4d4c}.highlight .c1,.highlight .cm,.highlight .cp,.highlight .cs{color:#8e908c}.highlight .gd{color:#c82829}.highlight .ge{font-style:italic}.highlight .gh{color:#4d4d4c}.highlight .gi{color:#718c00}.highlight .gp{color:#8e908c}.highlight .gu{color:#3e999f}.highlight .kc,.highlight .kd{color:#8959a8}.highlight .kn{color:#3e999f}.highlight .kp,.highlight .kr{color:#8959a8}.highlight .kt{color:#eab700}.highlight .ld{color:#718c00}.highlight .m{color:#f5871f}.highlight .s{color:#718c00}.highlight .na{color:#4271ae}.highlight .nb{color:#4d4d4c}.highlight .nc{color:#eab700}.highlight .no{color:#c82829}.highlight .nd{color:#3e999f}.highlight .ni{color:#4d4d4c}.highlight .ne{color:#c82829}.highlight .nf{color:#4271ae}.highlight .nl{color:#4d4d4c}.highlight .nn{color:#eab700}.highlight .nx{color:#4271ae}.highlight .py{color:#4d4d4c}.highlight .nt{color:#3e999f}.highlight .nv{color:#c82829}.highlight .ow{color:#3e999f}.highlight .w{color:#4d4d4c}.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:#f5871f}.highlight .sb{color:#718c00}.highlight .sc{color:#4d4d4c}.highlight .sd{color:#8e908c}.highlight .s2{color:#718c00}.highlight .se{color:#f5871f}.highlight .sh{color:#718c00}.highlight .si{color:#f5871f}.highlight .s1,.highlight .sr,.highlight .ss,.highlight .sx{color:#718c00}.highlight .bp{color:#4d4d4c}.highlight .vc,.highlight .vg,.highlight .vi{color:#c82829}.highlight .il{color:#f5871f}.highlight .o+.err{color:#4271ae}
/* site and markdown styles */
html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}
html{-webkit-font-smoothing:antialiased}
body{font-size:16px; margin:5vw 5vw 0;color:#111;font-family:-apple-system,BlinkMacSystemFont,sans-serif}
h1,h2,h3,h4,h5,h6{font-size:1em}
h2{margin-top:12vw}
p{font-family:Athelas,Georgia,serif}
pre code{display:table}
code, pre{font-family: monospace, monospace;font-size: 1em}
code, .highlight pre{font-size: .9em}
#contents + ul{text-decoration:none;padding-left:20px}
.black-link, #contents + ul li a{color:#000;text-decoration:none}
.black-link, #contents + ul li a:hover{text-decoration:underline}
.highlight{margin:1rem 0}
</style>
<h1 style="margin-bottom: 12vw; font-size: 1em; font-weight: normal">
React Patterns
<span style="color: #aaa">
[<a href="https://github.com/chantastic/reactpatterns.com/issues" class="black-link">on github</a>]
</span>
<div style="float: right; margin-top: 1rem; margin-bottom: 1rem">
<a href="https://learnreact.com/courses/2018-essential-react?utm_source=reactpatterns&utm_medium=ad&utm_campaign=standalone_resources&utm_content=function-components" target="_blank" rel="noopener" style="display: flex; line-height: 1.25; font-size: 12px; box-sizing: border-box; text-decoration: none; color: #222; flex-direction: column">
<div style="box-sizing: border-box; border: 1px solid lightgray; overflow: hidden">
<img src="./images/learn-react-in-1-hour.png" alt="Learn React in 1 hour" height="105" width="200" style="display: block" />
</div>
<span>learnreact.com</span>
</a>
</div>
</h1>
<div style="max-width: 800px">
<h2 id="contents">Contents</h2>
<ul>
<li><a href="#stateless-function">Stateless function</a></li>
<li><a href="#jsx-spread-attributes">JSX spread attributes</a></li>
<li><a href="#destructuring-arguments">Destructuring arguments</a></li>
<li><a href="#conditional-rendering">Conditional rendering</a></li>
<li><a href="#children-types">Children types</a></li>
<li><a href="#array-as-children">Array as children</a></li>
<li><a href="#function-as-children">Function as children</a></li>
<li><a href="#render-callback">Render callback</a></li>
<li><a href="#children-pass-through">Children pass-through</a></li>
<li><a href="#proxy-component">Proxy component</a></li>
<li><a href="#style-component">Style component</a></li>
<li><a href="#event-switch">Event switch</a></li>
<li><a href="#layout-component">Layout component</a></li>
<li><a href="#container-component">Container component</a></li>
<li><a href="#higher-order-component">Higher-order component</a></li>
<li><a href="#state-hoisting">State hoisting</a></li>
<li><a href="#controlled-input">Controlled input</a></li>
</ul>
<h2 id="stateless-function">Stateless function</h2>
<p><a href="https://facebook.github.io/react/docs/components-and-props.html">Stateless functions</a> are a brilliant way to define highly reusable components. They don’t hold <code>state</code>; they’re just functions.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">const</span> <span class="nx">Greeting</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="nx">Hi</span> <span class="nx">there</span><span class="o">!<</span><span class="err">/div></span>
</pre></div>
</code></pre>
<p>They get passed <code>props</code> and <code>context</code>.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">const</span> <span class="nx">Greeting</span> <span class="o">=</span> <span class="p">(</span><span class="nx">props</span><span class="p">,</span> <span class="nx">context</span><span class="p">)</span> <span class="o">=></span>
<span class="o"><</span><span class="nx">div</span> <span class="nx">style</span><span class="o">=</span><span class="p">{{</span><span class="nx">color</span><span class="o">:</span> <span class="nx">context</span><span class="p">.</span><span class="nx">color</span><span class="p">}}</span><span class="o">></span><span class="nx">Hi</span> <span class="p">{</span><span class="nx">props</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span><span class="o">!<</span><span class="err">/div></span>
</pre></div>
</code></pre>
<p>They can define local variables, where a function block is used.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">const</span> <span class="nx">Greeting</span> <span class="o">=</span> <span class="p">(</span><span class="nx">props</span><span class="p">,</span> <span class="nx">context</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kr">const</span> <span class="nx">style</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">fontWeight</span><span class="o">:</span> <span class="s2">"bold"</span><span class="p">,</span>
<span class="nx">color</span><span class="o">:</span> <span class="nx">context</span><span class="p">.</span><span class="nx">color</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">return</span> <span class="o"><</span><span class="nx">div</span> <span class="nx">style</span><span class="o">=</span><span class="p">{</span><span class="nx">style</span><span class="p">}</span><span class="o">></span><span class="p">{</span><span class="nx">props</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span><span class="o"><</span><span class="err">/div></span>
<span class="p">}</span>
</pre></div>
</code></pre>
<p>But you could get the same result by using other functions.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">const</span> <span class="nx">getStyle</span> <span class="o">=</span> <span class="nx">context</span> <span class="o">=></span> <span class="p">({</span>
<span class="nx">fontWeight</span><span class="o">:</span> <span class="s2">"bold"</span><span class="p">,</span>
<span class="nx">color</span><span class="o">:</span> <span class="nx">context</span><span class="p">.</span><span class="nx">color</span><span class="p">,</span>
<span class="p">})</span>
<span class="kr">const</span> <span class="nx">Greeting</span> <span class="o">=</span> <span class="p">(</span><span class="nx">props</span><span class="p">,</span> <span class="nx">context</span><span class="p">)</span> <span class="o">=></span>
<span class="o"><</span><span class="nx">div</span> <span class="nx">style</span><span class="o">=</span><span class="p">{</span><span class="nx">getStyle</span><span class="p">(</span><span class="nx">context</span><span class="p">)}</span><span class="o">></span><span class="p">{</span><span class="nx">props</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span><span class="o"><</span><span class="err">/div></span>
</pre></div>
</code></pre>
<p>They can have defined <code>defaultProps</code>, <code>propTypes</code> and <code>contextTypes</code>.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="nx">Greeting</span><span class="p">.</span><span class="nx">propTypes</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">name</span><span class="o">:</span> <span class="nx">PropTypes</span><span class="p">.</span><span class="nx">string</span><span class="p">.</span><span class="nx">isRequired</span>
<span class="p">}</span>
<span class="nx">Greeting</span><span class="p">.</span><span class="nx">defaultProps</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">name</span><span class="o">:</span> <span class="s2">"Guest"</span>
<span class="p">}</span>
<span class="nx">Greeting</span><span class="p">.</span><span class="nx">contextTypes</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">color</span><span class="o">:</span> <span class="nx">PropTypes</span><span class="p">.</span><span class="nx">string</span>
<span class="p">}</span>
</pre></div>
</code></pre>
<h2 id="jsx-spread-attributes">JSX spread attributes</h2>
<p>Spread Attributes is a JSX feature. It’s syntactic sugar for passing all of an object’s properties as JSX attributes.</p>
<p>These two examples are equivalent.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="c1">// props written as attributes</span>
<span class="o"><</span><span class="nx">main</span> <span class="nx">className</span><span class="o">=</span><span class="s2">"main"</span> <span class="nx">role</span><span class="o">=</span><span class="s2">"main"</span><span class="o">></span><span class="p">{</span><span class="nx">children</span><span class="p">}</span><span class="o"><</span><span class="err">/main></span>
<span class="c1">// props "spread" from object</span>
<span class="o"><</span><span class="nx">main</span> <span class="p">{...{</span><span class="nx">className</span><span class="o">:</span> <span class="s2">"main"</span><span class="p">,</span> <span class="nx">role</span><span class="o">:</span> <span class="s2">"main"</span><span class="p">,</span> <span class="nx">children</span><span class="p">}}</span> <span class="o">/></span>
</pre></div>
</code></pre>
<p>Use this to forward <code>props</code> to underlying components.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">const</span> <span class="nx">FancyDiv</span> <span class="o">=</span> <span class="nx">props</span> <span class="o">=></span>
<span class="o"><</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">"fancy"</span> <span class="p">{...</span><span class="nx">props</span><span class="p">}</span> <span class="o">/></span>
</pre></div>
</code></pre>
<p>Now, I can expect <code>FancyDiv</code> to add the attributes it’s concerned with as well as those it’s not.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">FancyDiv</span> <span class="nx">data</span><span class="o">-</span><span class="nx">id</span><span class="o">=</span><span class="s2">"my-fancy-div"</span><span class="o">></span><span class="nx">So</span> <span class="nx">Fancy</span><span class="o"><</span><span class="err">/FancyDiv></span>
<span class="c1">// output: <div class="fancy" data-id="my-fancy-div">So Fancy</div></span>
</pre></div>
</code></pre>
<p>Keep in mind that order matters. If <code>props.className</code> is defined, it’ll clobber the <code>className</code> defined by <code>FancyDiv</code></p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">FancyDiv</span> <span class="nx">className</span><span class="o">=</span><span class="s2">"my-fancy-div"</span> <span class="o">/></span>
<span class="c1">// output: <div className="my-fancy-div"></div></span>
</pre></div>
</code></pre>
<p>We can make <code>FancyDiv</code>s className always “win” by placing it after the spread props <code>({...props})</code>.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="c1">// my `className` clobbers your `className`</span>
<span class="kr">const</span> <span class="nx">FancyDiv</span> <span class="o">=</span> <span class="nx">props</span> <span class="o">=></span>
<span class="o"><</span><span class="nx">div</span> <span class="p">{...</span><span class="nx">props</span><span class="p">}</span> <span class="nx">className</span><span class="o">=</span><span class="s2">"fancy"</span> <span class="o">/></span>
</pre></div>
</code></pre>
<p>You should handle these types of props gracefully. In this case, I’ll merge the author’s <code>props.className</code> with the <code>className</code> needed to style my component.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">const</span> <span class="nx">FancyDiv</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">className</span><span class="p">,</span> <span class="p">...</span><span class="nx">props</span> <span class="p">})</span> <span class="o">=></span>
<span class="o"><</span><span class="nx">div</span>
<span class="nx">className</span><span class="o">=</span><span class="p">{[</span><span class="s2">"fancy"</span><span class="p">,</span> <span class="nx">className</span><span class="p">].</span><span class="nx">join</span><span class="p">(</span><span class="s1">' '</span><span class="p">)}</span>
<span class="p">{...</span><span class="nx">props</span><span class="p">}</span>
<span class="o">/></span>
</pre></div>
</code></pre>
<h2 id="destructuring-arguments">destructuring arguments</h2>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">Destructuring assignment</a> is an ES2015 feature. It pairs nicely with <code>props</code> in Stateless Functions.</p>
<p>These examples are equivalent.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">const</span> <span class="nx">Greeting</span> <span class="o">=</span> <span class="nx">props</span> <span class="o">=></span> <span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="nx">Hi</span> <span class="p">{</span><span class="nx">props</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span><span class="o">!<</span><span class="err">/div></span>
<span class="kr">const</span> <span class="nx">Greeting</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">name</span> <span class="p">})</span> <span class="o">=></span> <span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="nx">Hi</span> <span class="p">{</span><span class="nx">name</span><span class="p">}</span><span class="o">!<</span><span class="err">/div></span>
</pre></div>
</code></pre>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters">rest parameter syntax</a> (<code>...</code>) allows you to collect all the remaining properties in a new object.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">const</span> <span class="nx">Greeting</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">name</span><span class="p">,</span> <span class="p">...</span><span class="nx">props</span> <span class="p">})</span> <span class="o">=></span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="nx">Hi</span> <span class="p">{</span><span class="nx">name</span><span class="p">}</span><span class="o">!<</span><span class="err">/div></span>
</pre></div>
</code></pre>
<p>In turn, this object can use <a href="#jsx-spread-attributes">JSX Spread Attributes</a> to forward <code>props</code> to the composed component.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">const</span> <span class="nx">Greeting</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">name</span><span class="p">,</span> <span class="p">...</span><span class="nx">props</span> <span class="p">})</span> <span class="o">=></span>
<span class="o"><</span><span class="nx">div</span> <span class="p">{...</span><span class="nx">props</span><span class="p">}</span><span class="o">></span><span class="nx">Hi</span> <span class="p">{</span><span class="nx">name</span><span class="p">}</span><span class="o">!<</span><span class="err">/div></span>
</pre></div>
</code></pre>
<p>Avoid forwarding non-DOM <code>props</code> to composed components. Destructuring makes this very easy because you can create a new <code>props</code> object <strong>without</strong> component-specific <code>props</code>.</p>
<h2 id="conditional-rendering">conditional rendering</h2>
<p>You can’t use regular if/else conditions inside a component definition. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">The conditional (ternary) operator</a> is your friend.</p>
<p><code>if</code></p>
<pre><code class="language-js"><div class="highlight"><pre><span class="p">{</span><span class="nx">condition</span> <span class="o">&&</span> <span class="o"><</span><span class="nx">span</span><span class="o">></span><span class="nx">Rendered</span> <span class="nx">when</span> <span class="err">`</span><span class="nx">truthy</span><span class="err">`</span><span class="o"><</span><span class="err">/span> }</span>
</pre></div>
</code></pre>
<p><code>unless</code></p>
<pre><code class="language-js"><div class="highlight"><pre><span class="p">{</span><span class="nx">condition</span> <span class="o">||</span> <span class="o"><</span><span class="nx">span</span><span class="o">></span><span class="nx">Rendered</span> <span class="nx">when</span> <span class="err">`</span><span class="nx">falsey</span><span class="err">`</span><span class="o"><</span><span class="err">/span> }</span>
</pre></div>
</code></pre>
<p><code>if-else</code> (tidy one-liners)</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="p">{</span><span class="nx">condition</span>
<span class="o">?</span> <span class="o"><</span><span class="nx">span</span><span class="o">></span><span class="nx">Rendered</span> <span class="nx">when</span> <span class="err">`</span><span class="nx">truthy</span><span class="err">`</span><span class="o"><</span><span class="err">/span></span>
<span class="o">:</span> <span class="o"><</span><span class="nx">span</span><span class="o">></span><span class="nx">Rendered</span> <span class="nx">when</span> <span class="err">`</span><span class="nx">falsey</span><span class="err">`</span><span class="o"><</span><span class="err">/span></span>
<span class="p">}</span>
</pre></div>
</code></pre>
<p><code>if-else</code> (big blocks)</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="p">{</span><span class="nx">condition</span> <span class="o">?</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">span</span><span class="o">></span>
<span class="nx">Rendered</span> <span class="nx">when</span> <span class="err">`</span><span class="nx">truthy</span><span class="err">`</span>
<span class="o"><</span><span class="err">/span></span>
<span class="p">)</span> <span class="o">:</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">span</span><span class="o">></span>
<span class="nx">Rendered</span> <span class="nx">when</span> <span class="err">`</span><span class="nx">falsey</span><span class="err">`</span>
<span class="o"><</span><span class="err">/span></span>
<span class="p">)}</span>
</pre></div>
</code></pre>
<h2 id="children-types">Children types</h2>
<p>React can render <code>children</code> of many types. In most cases it’s either an <code>array</code> or a <code>string</code>.</p>
<p><code>string</code></p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="nx">Hello</span> <span class="nx">World</span><span class="o">!</span>
<span class="o"><</span><span class="err">/div></span>
</pre></div>
</code></pre>
<p><code>array</code></p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="p">{[</span><span class="s2">"Hello "</span><span class="p">,</span> <span class="o"><</span><span class="nx">span</span><span class="o">></span><span class="nx">World</span><span class="o"><</span><span class="err">/span>, "!"]}</span>
<span class="o"><</span><span class="err">/div></span>
</pre></div>
</code></pre>
<p>Functions may be used as children. However, it requires <a href="#render-callback">coordination with the parent component</a> to be useful.</p>
<p><code>function</code></p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="p">{(()</span> <span class="o">=></span> <span class="p">{</span> <span class="k">return</span> <span class="s2">"hello world!"</span><span class="p">})()}</span>
<span class="o"><</span><span class="err">/div></span>
</pre></div>
</code></pre>
<h2 id="array-as-children">Array as children</h2>
<p>Providing an array as <code>children</code> is a very common. It’s how lists are drawn in React.</p>
<p>We use <code>map()</code> to create an array of React Elements for every value in the array.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">ul</span><span class="o">></span>
<span class="p">{[</span><span class="s2">"first"</span><span class="p">,</span> <span class="s2">"second"</span><span class="p">].</span><span class="nx">map</span><span class="p">((</span><span class="nx">item</span><span class="p">)</span> <span class="o">=></span> <span class="p">(</span>
<span class="o"><</span><span class="nx">li</span><span class="o">></span><span class="p">{</span><span class="nx">item</span><span class="p">}</span><span class="o"><</span><span class="err">/li></span>
<span class="p">))}</span>
<span class="o"><</span><span class="err">/ul></span>
</pre></div>
</code></pre>
<p>That’s equivalent to providing a literal <code>array</code>.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">ul</span><span class="o">></span>
<span class="p">{[</span>
<span class="o"><</span><span class="nx">li</span><span class="o">></span><span class="nx">first</span><span class="o"><</span><span class="err">/li>,</span>
<span class="o"><</span><span class="nx">li</span><span class="o">></span><span class="nx">second</span><span class="o"><</span><span class="err">/li>,</span>
<span class="p">]}</span>
<span class="o"><</span><span class="err">/ul></span>
</pre></div>
</code></pre>
<p>This pattern can be combined with destructuring, JSX Spread Attributes, and other components, for some serious terseness.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="p">{</span><span class="nx">arrayOfMessageObjects</span><span class="p">.</span><span class="nx">map</span><span class="p">(({</span> <span class="nx">id</span><span class="p">,</span> <span class="p">...</span><span class="nx">message</span> <span class="p">})</span> <span class="o">=></span>
<span class="o"><</span><span class="nx">Message</span> <span class="nx">key</span><span class="o">=</span><span class="p">{</span><span class="nx">id</span><span class="p">}</span> <span class="p">{...</span><span class="nx">message</span><span class="p">}</span> <span class="o">/></span>
<span class="p">)}</span>
<span class="o"><</span><span class="err">/div></span>
</pre></div>
</code></pre>
<h2 id="function-as-children">Function as children</h2>
<p>Using a function as <code>children</code> isn’t inherently useful.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="p">{()</span> <span class="o">=></span> <span class="p">{</span> <span class="k">return</span> <span class="s2">"hello world!"</span><span class="p">}()}</span><span class="o"><</span><span class="err">/div></span>
</pre></div>
</code></pre>
<p>However, it can be used in component authoring for some serious power. This technique is commonly referred to as <code>render callbacks</code>.</p>
<p>This is a powerful technique used by libraries like <a href="https://github.com/chenglou/react-motion">ReactMotion</a>. When applied, rendering logic can be kept in the owner component, instead of being delegated.</p>
<p>See <a href="#render-callback">Render callbacks</a>, for more details.</p>
<h2 id="render-callback">Render callback</h2>
<p>Here’s a component that uses a Render callback. It’s not useful, but it’s an easy illustration to start with.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">const</span> <span class="nx">Width</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">children</span> <span class="p">})</span> <span class="o">=></span> <span class="nx">children</span><span class="p">(</span><span class="mi">500</span><span class="p">)</span>
</pre></div>
</code></pre>
<p>The component calls <code>children</code> as a function, with some number of arguments. Here, it’s the number <code>500</code>.</p>
<p>To use this component, we give it a <a href="#function-as-children">function as <code>children</code></a>.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">Width</span><span class="o">></span>
<span class="p">{</span><span class="nx">width</span> <span class="o">=></span> <span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="nb">window</span> <span class="nx">is</span> <span class="p">{</span><span class="nx">width</span><span class="p">}</span><span class="o"><</span><span class="err">/div>}</span>
<span class="o"><</span><span class="err">/Width></span>
</pre></div>
</code></pre>
<p>We get this output.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="nb">window</span> <span class="nx">is</span> <span class="mi">500</span><span class="o"><</span><span class="err">/div></span>
</pre></div>
</code></pre>
<p>With this setup, we can use this <code>width</code> to make rendering decisions.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">Width</span><span class="o">></span>
<span class="p">{</span><span class="nx">width</span> <span class="o">=></span>
<span class="nx">width</span> <span class="o">></span> <span class="mi">600</span>
<span class="o">?</span> <span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="nx">min</span><span class="o">-</span><span class="nx">width</span> <span class="nx">requirement</span> <span class="nx">met</span><span class="o">!<</span><span class="err">/div></span>
<span class="o">:</span> <span class="kc">null</span>
<span class="p">}</span>
<span class="o"><</span><span class="err">/Width></span>
</pre></div>
</code></pre>
<p>If we plan to use this condition a lot, we can define another components to encapsulate the reused logic.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">const</span> <span class="nx">MinWidth</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">width</span><span class="o">:</span> <span class="nx">minWidth</span><span class="p">,</span> <span class="nx">children</span> <span class="p">})</span> <span class="o">=></span>
<span class="o"><</span><span class="nx">Width</span><span class="o">></span>
<span class="p">{</span><span class="nx">width</span> <span class="o">=></span>
<span class="nx">width</span> <span class="o">></span> <span class="nx">minWidth</span>
<span class="o">?</span> <span class="nx">children</span>
<span class="o">:</span> <span class="kc">null</span>
<span class="p">}</span>
<span class="o"><</span><span class="err">/Width></span>
</pre></div>
</code></pre>
<p>Obviously a static <code>Width</code> component isn’t useful but one that watches the browser window is. Here’s a sample implementation.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">class</span> <span class="nx">WindowWidth</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
<span class="nx">constructor</span><span class="p">()</span> <span class="p">{</span>
<span class="kr">super</span><span class="p">()</span>
<span class="k">this</span><span class="p">.</span><span class="nx">state</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">width</span><span class="o">:</span> <span class="mi">0</span> <span class="p">}</span>
<span class="p">}</span>
<span class="nx">componentDidMount</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">(</span>
<span class="p">{</span><span class="nx">width</span><span class="o">:</span> <span class="nb">window</span><span class="p">.</span><span class="nx">innerWidth</span><span class="p">},</span>
<span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span>
<span class="s2">"resize"</span><span class="p">,</span>
<span class="p">({</span> <span class="nx">target</span> <span class="p">})</span> <span class="o">=></span>
<span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span><span class="nx">width</span><span class="o">:</span> <span class="nx">target</span><span class="p">.</span><span class="nx">innerWidth</span><span class="p">})</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="p">}</span>
<span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">children</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">width</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</code></pre>
<p>Many developers favor <a href="#higher-order-component">Higher Order Components</a> for this type of functionality. It’s a matter of preference.</p>
<h2 id="children-pass-through">Children pass-through</h2>
<p>You might create a component designed to apply <code>context</code> and render its <code>children</code>.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">class</span> <span class="nx">SomeContextProvider</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
<span class="nx">getChildContext</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">{</span><span class="nx">some</span><span class="o">:</span> <span class="s2">"context"</span><span class="p">}</span>
<span class="p">}</span>
<span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// how best do we return `children`?</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</code></pre>
<p>You’re faced with a decision. Wrap <code>children</code> in an extraneous <code><div /></code> or return <code>children</code> directly. The first options gives you extra markup (which can break some stylesheets). The second will result in unhelpful errors.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="c1">// option 1: extra div</span>
<span class="k">return</span> <span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="p">{</span><span class="nx">children</span><span class="p">}</span><span class="o"><</span><span class="err">/div></span>
<span class="c1">// option 2: unhelpful errors</span>
<span class="k">return</span> <span class="nx">children</span>
</pre></div>
</code></pre>
<p>It’s best to treat <code>children</code> as an opaque data type. React provides <code>React.Children</code> for dealing with <code>children</code> appropriately.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="k">return</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Children</span><span class="p">.</span><span class="nx">only</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">children</span><span class="p">)</span>
</pre></div>
</code></pre>
<h2 id="proxy-component">Proxy component</h2>
<p><em>(I’m not sure if this name makes sense)</em></p>
<p>Buttons are everywhere in web apps. And every one of them must have the <code>type</code> attribute set to “button”.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">button</span> <span class="nx">type</span><span class="o">=</span><span class="s2">"button"</span><span class="o">></span>
</pre></div>
</code></pre>
<p>Writing this attribute hundreds of times is error prone. We can write a higher level component to proxy <code>props</code> to a lower-level <code>button</code> component.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">const</span> <span class="nx">Button</span> <span class="o">=</span> <span class="nx">props</span> <span class="o">=></span>
<span class="o"><</span><span class="nx">button</span> <span class="nx">type</span><span class="o">=</span><span class="s2">"button"</span> <span class="p">{...</span><span class="nx">props</span><span class="p">}</span><span class="o">></span>
</pre></div>
</code></pre>
<p>We can use <code>Button</code> in place of <code>button</code> and ensure that the <code>type</code> attribute is consistently applied everywhere.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">Button</span> <span class="o">/></span>
<span class="c1">// <button type="button"><button></span>
<span class="o"><</span><span class="nx">Button</span> <span class="nx">className</span><span class="o">=</span><span class="s2">"CTA"</span><span class="o">></span><span class="nx">Send</span> <span class="nx">Money</span><span class="o"><</span><span class="err">/Button></span>
<span class="c1">// <button type="button" class="CTA">Send Money</button></span>
</pre></div>
</code></pre>
<h2 id="style-component">Style component</h2>
<p>This is a <a href="#proxy-component">Proxy component</a> applied to the practices of style.</p>
<p>Say we have a button. It uses classes to be styled as a “primary” button.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">button</span> <span class="nx">type</span><span class="o">=</span><span class="s2">"button"</span> <span class="nx">className</span><span class="o">=</span><span class="s2">"btn btn-primary"</span><span class="o">></span>
</pre></div>
</code></pre>
<p>We can generate this output using a couple single-purpose components.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">import</span> <span class="nx">classnames</span> <span class="nx">from</span> <span class="s1">'classnames'</span>
<span class="kr">const</span> <span class="nx">PrimaryBtn</span> <span class="o">=</span> <span class="nx">props</span> <span class="o">=></span>
<span class="o"><</span><span class="nx">Btn</span> <span class="p">{...</span><span class="nx">props</span><span class="p">}</span> <span class="nx">primary</span> <span class="o">/></span>
<span class="kr">const</span> <span class="nx">Btn</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">className</span><span class="p">,</span> <span class="nx">primary</span><span class="p">,</span> <span class="p">...</span><span class="nx">props</span> <span class="p">})</span> <span class="o">=></span>
<span class="o"><</span><span class="nx">button</span>
<span class="nx">type</span><span class="o">=</span><span class="s2">"button"</span>
<span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="nx">classnames</span><span class="p">(</span>
<span class="s2">"btn"</span><span class="p">,</span>
<span class="nx">primary</span> <span class="o">&&</span> <span class="s2">"btn-primary"</span><span class="p">,</span>
<span class="nx">className</span>
<span class="p">)}</span>
<span class="p">{...</span><span class="nx">props</span><span class="p">}</span>
<span class="o">/></span>
</pre></div>
</code></pre>
<p>It can help to visualize this.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="nx">PrimaryBtn</span><span class="p">()</span>
<span class="err">↳</span> <span class="nx">Btn</span><span class="p">({</span><span class="nx">primary</span><span class="o">:</span> <span class="kc">true</span><span class="p">})</span>
<span class="err">↳</span> <span class="nx">Button</span><span class="p">({</span><span class="nx">className</span><span class="o">:</span> <span class="s2">"btn btn-primary"</span><span class="p">},</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">"button"</span><span class="p">})</span>
<span class="err">↳</span> <span class="s1">'<button type="button" class="btn btn-primary"></button>'</span>
</pre></div>
</code></pre>
<p>Using these components, all of these result in the same output.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">PrimaryBtn</span> <span class="o">/></span>
<span class="o"><</span><span class="nx">Btn</span> <span class="nx">primary</span> <span class="o">/></span>
<span class="o"><</span><span class="nx">button</span> <span class="nx">type</span><span class="o">=</span><span class="s2">"button"</span> <span class="nx">className</span><span class="o">=</span><span class="s2">"btn btn-primary"</span> <span class="o">/></span>
</pre></div>
</code></pre>
<p>This can be a huge boon to style maintenance. It isolates all concerns of style to a single component.</p>
<h2 id="event-switch">Event switch</h2>
<p>When writing event handlers it’s common to adopt the <code>handle{eventName}</code> naming convention.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="nx">handleClick</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span> <span class="cm">/* do something */</span> <span class="p">}</span>
</pre></div>
</code></pre>
<p>For components that handle several event types, these function names can be repetitive. The names themselves might not provide much value, as they simply proxy to other actions/functions.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="nx">handleClick</span><span class="p">()</span> <span class="p">{</span> <span class="nx">require</span><span class="p">(</span><span class="s2">"./actions/doStuff"</span><span class="p">)(</span><span class="cm">/* action stuff */</span><span class="p">)</span> <span class="p">}</span>
<span class="nx">handleMouseEnter</span><span class="p">()</span> <span class="p">{</span> <span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span> <span class="nx">hovered</span><span class="o">:</span> <span class="kc">true</span> <span class="p">})</span> <span class="p">}</span>
<span class="nx">handleMouseLeave</span><span class="p">()</span> <span class="p">{</span> <span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span> <span class="nx">hovered</span><span class="o">:</span> <span class="kc">false</span> <span class="p">})</span> <span class="p">}</span>
</pre></div>
</code></pre>
<p>Consider writing a single event handler for your component and switching on <code>event.type</code>.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="nx">handleEvent</span><span class="p">({</span><span class="nx">type</span><span class="p">})</span> <span class="p">{</span>
<span class="k">switch</span><span class="p">(</span><span class="nx">type</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="s2">"click"</span><span class="o">:</span>
<span class="k">return</span> <span class="nx">require</span><span class="p">(</span><span class="s2">"./actions/doStuff"</span><span class="p">)(</span><span class="cm">/* action dates */</span><span class="p">)</span>
<span class="k">case</span> <span class="s2">"mouseenter"</span><span class="o">:</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span> <span class="nx">hovered</span><span class="o">:</span> <span class="kc">true</span> <span class="p">})</span>
<span class="k">case</span> <span class="s2">"mouseleave"</span><span class="o">:</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span> <span class="nx">hovered</span><span class="o">:</span> <span class="kc">false</span> <span class="p">})</span>
<span class="k">default</span><span class="o">:</span>
<span class="k">return</span> <span class="nx">console</span><span class="p">.</span><span class="nx">warn</span><span class="p">(</span><span class="err">`</span><span class="nx">No</span> <span class="k">case</span> <span class="k">for</span> <span class="nx">event</span> <span class="nx">type</span> <span class="s2">"${type}"</span><span class="err">`</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</code></pre>
<p>Alternatively, for simple components, you can call imported actions/functions directly from components, using arrow functions.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">div</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="o">=></span> <span class="nx">someImportedAction</span><span class="p">({</span> <span class="nx">action</span><span class="o">:</span> <span class="s2">"DO_STUFF"</span> <span class="p">})}</span>
</pre></div>
</code></pre>
<p>Don’t fret about performance optimizations until you have problems. Seriously don’t.</p>
<h2 id="layout-component">Layout component</h2>
<p>Layout components result in some form of static DOM element. It might not need to update frequently, if ever.</p>
<p>Consider a component that renders two <code>children</code> side-by-side.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">HorizontalSplit</span>
<span class="nx">leftSide</span><span class="o">=</span><span class="p">{</span><span class="o"><</span><span class="nx">SomeSmartComponent</span> <span class="o">/></span><span class="p">}</span>
<span class="nx">rightSide</span><span class="o">=</span><span class="p">{</span><span class="o"><</span><span class="nx">AnotherSmartComponent</span> <span class="o">/></span><span class="p">}</span>
<span class="o">/></span>
</pre></div>
</code></pre>
<p>We can aggressively optimize this component.</p>
<p>While <code>HorizontalSplit</code> will be <code>parent</code> to both components, it will never be their <code>owner</code>. We can tell it to update never, without interrupting the lifecycle of the components inside.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">class</span> <span class="nx">HorizontalSplit</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
<span class="nx">shouldComponentUpdate</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="kc">false</span>
<span class="p">}</span>
<span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
<span class="o"><</span><span class="nx">FlexContainer</span><span class="o">></span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">leftSide</span><span class="p">}</span><span class="o"><</span><span class="err">/div></span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">rightSide</span><span class="p">}</span><span class="o"><</span><span class="err">/div></span>
<span class="o"><</span><span class="err">/FlexContainer></span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</code></pre>
<h2 id="container-component">Container component</h2>
<p>“A container does data fetching and then renders its corresponding sub-component. That’s it.”—<a href="https://twitter.com/jasonbonta">Jason Bonta</a></p>
<p>Given this reusable <code>CommentList</code> component.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">const</span> <span class="nx">CommentList</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">comments</span> <span class="p">})</span> <span class="o">=></span>
<span class="o"><</span><span class="nx">ul</span><span class="o">></span>
<span class="p">{</span><span class="nx">comments</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">comment</span> <span class="o">=></span>
<span class="o"><</span><span class="nx">li</span><span class="o">></span><span class="p">{</span><span class="nx">comment</span><span class="p">.</span><span class="nx">body</span><span class="p">}</span><span class="o">-</span><span class="p">{</span><span class="nx">comment</span><span class="p">.</span><span class="nx">author</span><span class="p">}</span><span class="o"><</span><span class="err">/li></span>
<span class="p">)}</span>
<span class="o"><</span><span class="err">/ul></span>
</pre></div>
</code></pre>
<p>We can create a new component responsible for fetching data and rendering the stateless <code>CommentList</code> component.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">class</span> <span class="nx">CommentListContainer</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
<span class="nx">constructor</span><span class="p">()</span> <span class="p">{</span>
<span class="kr">super</span><span class="p">()</span>
<span class="k">this</span><span class="p">.</span><span class="nx">state</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">comments</span><span class="o">:</span> <span class="p">[]</span> <span class="p">}</span>
<span class="p">}</span>
<span class="nx">componentDidMount</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">$</span><span class="p">.</span><span class="nx">ajax</span><span class="p">({</span>
<span class="nx">url</span><span class="o">:</span> <span class="s2">"/my-comments.json"</span><span class="p">,</span>
<span class="nx">dataType</span><span class="o">:</span> <span class="s1">'json'</span><span class="p">,</span>
<span class="nx">success</span><span class="o">:</span> <span class="nx">comments</span> <span class="o">=></span>
<span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span><span class="nx">comments</span><span class="o">:</span> <span class="nx">comments</span><span class="p">});</span>
<span class="p">})</span>
<span class="p">}</span>
<span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="o"><</span><span class="nx">CommentList</span> <span class="nx">comments</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">comments</span><span class="p">}</span> <span class="o">/></span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</code></pre>
<p>We can write different containers for different application contexts.</p>
<h2 id="higher-order-component">Higher-order component</h2>
<p>A <a href="https://en.wikipedia.org/wiki/Higher-order_function">higher-order function</a> is a function that takes and/or returns a function. It’s not more complicated than that. So, what’s a higher-order component?</p>
<p>If you’re already using <a href="#container-component">container components</a>, these are just generic containers, wrapped up in a function.</p>
<p>Let’s start with our stateless <code>Greeting</code> component.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">const</span> <span class="nx">Greeting</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">name</span> <span class="p">})</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">name</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="nx">Connecting</span><span class="p">...</span><span class="o"><</span><span class="err">/div> }</span>
<span class="k">return</span> <span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="nx">Hi</span> <span class="p">{</span><span class="nx">name</span><span class="p">}</span><span class="o">!<</span><span class="err">/div></span>
<span class="p">}</span>
</pre></div>
</code></pre>
<p>If it gets <code>props.name</code>, it’s gonna render that data. Otherwise it’ll say that it’s “Connecting…”. Now for the the higher-order bit.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">const</span> <span class="nx">Connect</span> <span class="o">=</span> <span class="nx">ComposedComponent</span> <span class="o">=></span>
<span class="kr">class</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
<span class="nx">constructor</span><span class="p">()</span> <span class="p">{</span>
<span class="kr">super</span><span class="p">()</span>
<span class="k">this</span><span class="p">.</span><span class="nx">state</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">name</span><span class="o">:</span> <span class="s2">""</span> <span class="p">}</span>
<span class="p">}</span>
<span class="nx">componentDidMount</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// this would fetch or connect to a store</span>
<span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span> <span class="nx">name</span><span class="o">:</span> <span class="s2">"Michael"</span> <span class="p">})</span>
<span class="p">}</span>
<span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">ComposedComponent</span>
<span class="p">{...</span><span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">}</span>
<span class="nx">name</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span>
<span class="o">/></span>
<span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</code></pre>
<p>This is just a function that returns component that renders the component we passed as an argument.</p>
<p>Last step, we need to wrap our our <code>Greeting</code> component in <code>Connect</code>.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">const</span> <span class="nx">ConnectedMyComponent</span> <span class="o">=</span> <span class="nx">Connect</span><span class="p">(</span><span class="nx">Greeting</span><span class="p">)</span>
</pre></div>
</code></pre>
<p>This is a powerful pattern for providing fetching and providing data to any number of <a href="#stateless-function">stateless function components</a>.</p>
<h2 id="state-hoisting">State hoisting</h2>
<p><a href="#stateless-function">Stateless functions</a> don’t hold state (as the name implies).</p>
<p>Events are changes in state.
Their data needs to be passed to stateful <a href="#container-component">container components</a> parents.</p>
<p>This is called “state hoisting”.
It’s accomplished by passing a callback from a container component to a child component.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">class</span> <span class="nx">NameContainer</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
<span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="o"><</span><span class="nx">Name</span> <span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="nx">newName</span> <span class="o">=></span> <span class="nx">alert</span><span class="p">(</span><span class="nx">newName</span><span class="p">)}</span> <span class="o">/></span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kr">const</span> <span class="nx">Name</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">onChange</span> <span class="p">})</span> <span class="o">=></span>
<span class="o"><</span><span class="nx">input</span> <span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="nx">e</span> <span class="o">=></span> <span class="nx">onChange</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">)}</span> <span class="o">/></span>
</pre></div>
</code></pre>
<p><code>Name</code> receives an <code>onChange</code> callback from <code>NameContainer</code> and calls on events.</p>
<p>The <code>alert</code> above makes for a terse demo but it’s not changing state.
Let’s change the internal state of <code>NameContainer</code>.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">class</span> <span class="nx">NameContainer</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
<span class="nx">constructor</span><span class="p">()</span> <span class="p">{</span>
<span class="kr">super</span><span class="p">()</span>
<span class="k">this</span><span class="p">.</span><span class="nx">state</span> <span class="o">=</span> <span class="p">{</span><span class="nx">name</span><span class="o">:</span> <span class="s2">""</span><span class="p">}</span>
<span class="p">}</span>
<span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="o"><</span><span class="nx">Name</span> <span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="nx">newName</span> <span class="o">=></span> <span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span><span class="nx">name</span><span class="o">:</span> <span class="nx">newName</span><span class="p">})}</span> <span class="o">/></span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</code></pre>
<p>The state is <em>hoisted</em> to the container, by the provided callback, where it’s used to update local state.
This sets a nice clear boundary and maximizes the re-usability of stateless function.</p>
<p>This pattern isn’t limited to stateless functions.
Because stateless function don’t have lifecycle events,
you’ll use this pattern with component classes as well.</p>
<p><em><a href="#controlled-input">Controlled input</a> is an important pattern to know for use with state hoisting</em></p>
<p><em>(It’s best to process the event object on the stateful component)</em></p>
<h2 id="controlled-input">Controlled input</h2>
<p>It’s hard to talk about controlled inputs in the abstract.
Let’s start with an uncontrolled (normal) input and go from there.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">input</span> <span class="nx">type</span><span class="o">=</span><span class="s2">"text"</span> <span class="o">/></span>
</pre></div>
</code></pre>
<p>When you fiddle with this input in the browser, you see your changes.
This is normal.</p>
<p>A controlled input disallows the DOM mutations that make this possible.
You set the <code>value</code> of the input in component-land and it doesn’t change in DOM-land.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="o"><</span><span class="nx">input</span> <span class="nx">type</span><span class="o">=</span><span class="s2">"text"</span> <span class="nx">value</span><span class="o">=</span><span class="s2">"This won't change. Try it."</span> <span class="o">/></span>
</pre></div>
</code></pre>
<p>Obviously static inputs aren’t very useful to your users.
So, we derive a <code>value</code> from state.</p>
<pre><code class="language-js"><div class="highlight"><pre><span class="kr">class</span> <span class="nx">ControlledNameInput</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
<span class="nx">constructor</span><span class="p">()</span> <span class="p">{</span>
<span class="kr">super</span><span class="p">()</span>
<span class="k">this</span><span class="p">.</span><span class="nx">state</span> <span class="o">=</span> <span class="p">{</span><span class="nx">name</span><span class="o">:</span> <span class="s2">""</span><span class="p">}</span>
<span class="p">}</span>
<span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="o"><</span><span class="nx">input</span> <span class="nx">type</span><span class="o">=</span><span class="s2">"text"</span> <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span> <span class="o">/></span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</code></pre>
<p>Then, changing the input is a matter of changing component state.</p>
<pre><code class="language-js"><div class="highlight"><pre> <span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">input</span>
<span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span>
<span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="nx">e</span> <span class="o">=></span> <span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span> <span class="nx">name</span><span class="o">:</span> <span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span> <span class="p">})}</span>
<span class="o">/></span>
<span class="p">)</span>
</pre></div>
</code></pre>
<p>This is a controlled input.
It only updates the DOM when state has changed in our component.
This is invaluable when creating consistent UIs.</p>
<p><em>If you’re using <a href="#stateless-function">stateless functions</a> for form elements,
read about using <a href="#state-hoisting">state hoisting</a> to move new state up the component tree.</em></p>
<footer style="margin-top: 3rem">
<p>
© Copyright 2017, <a href="" target="_blank" rel="noopener" class="black-link">Michael Chan</a>
</p>
</footer>
</div>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-56273983-4', 'auto');
ga('send', 'pageview');
</script>
</body>
</html>