~cytrogen/blog-public

ref: 88eebf3dfdd8ab819fa1a84e1976a8a75d5af2b6 blog-public/posts/d011.html -rw-r--r-- 138.0 KiB
88eebf3dCytrogen Deploy 2026-02-19 08:34:27 3 days ago
                                                                                
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
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
<!DOCTYPE html><html lang="zh" data-theme="dark"><head><meta charset="utf-8"><meta name="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>IBM 全栈开发【4】:React 创建前端应用 · Cytrogen 的个人博客</title><meta name="description" content="本文是 IBM 全栈开发课程的第四篇学习笔记,系统性地介绍了如何使用 React 和 ES6 构建前端应用。内容从 React 的基础概念(如JSX、组件化)和 ES6 核心语法(箭头函数、类)讲起,深入探讨了组件的状态(state)与属性(props)、完整的生命周期、父子组件间的数据通信,以及如何使用 Hooks 为函数式组件添加状态。此外,笔记还涵盖了 React 表单处理和使用 Redux 进行全局状态管理等进阶主题。这篇笔记为 React 初学者提供了一份从入门到进阶的完整学习路径和知识点梳理。"><link rel="icon" href="../favicon.png"><link rel="canonical" href="https://cytrogen.icu/posts/d011.html"><link rel="webmention" href="https://webmention.io/cytrogen.icu/webmention"><link rel="me" href="https://m.otter.homes/@Cytrogen"><link rel="me" href="https://github.com/cytrogen"><meta name="fediverse:creator" content="@Cytrogen@m.otter.homes"><link rel="preload" href="../fonts/opensans-regular-latin.woff2" as="font" type="font/woff2" crossorigin="anonymous"><style>@font-face {
  font-family: 'Open Sans';
  src: url('../fonts/opensans-regular-latin.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  size-adjust: 107%;
  ascent-override: 97%;
  descent-override: 25%;
  line-gap-override: 0%;
}
</style><script>(function() {
  try {
    // 优先级:用户选择 > 系统偏好 > 默认浅色
    const saved = localStorage.getItem('theme');
    const theme = saved || 
      (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
    
    document.documentElement.setAttribute('data-theme', theme);
    document.documentElement.style.colorScheme = theme;
  } catch (error) {
    // 失败时使用默认主题,不阻塞渲染
    document.documentElement.setAttribute('data-theme', 'light');
  }
})();
</script><link rel="stylesheet" href="../css/ares.css"><script data-netlify-skip-bundle="true">(function() {
  document.addEventListener('DOMContentLoaded', function() {
    const theme = document.documentElement.getAttribute('data-theme');
    const pageWrapper = document.getElementById('page-wrapper');
    if (pageWrapper && theme) {
      pageWrapper.setAttribute('data-theme', theme);
    }
  });
})();

</script><!-- hexo injector head_end start -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css">

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hexo-math@4.0.0/dist/style.css">
<!-- hexo injector head_end end --><meta name="generator" content="Hexo 8.1.1"><link rel="alternate" href="atom.xml" title="Cytrogen 的个人博客" type="application/atom+xml">
</head><body><div id="page-wrapper"><a class="skip-link" href="#main-content">跳到主要内容</a><div class="wrap"><header><a class="logo-link" href="../index.html"><img src="../favicon.png" alt="logo"></a><div class="h-card visually-hidden"><img class="u-photo" src="https://cytrogen.icu/favicon.png" alt="Cytrogen"><a class="p-name u-url u-uid" href="https://cytrogen.icu">Cytrogen</a><p class="p-note">Cytrogen 的个人博客,Cytrogen's Blog</p><a class="u-url" rel="me noopener" target="_blank" href="https://m.otter.homes/@Cytrogen">Mastodon</a><a class="u-url" rel="me noopener" target="_blank" href="https://github.com/cytrogen">GitHub</a></div><nav class="site-nav"><div class="nav-main"><div class="nav-primary"><ul class="nav-list hidden-mobile"><li class="nav-item"><a class="nav-link" href="../index.html">首页</a></li></ul><div class="nav-tools"><div class="language-menu"><button class="language-toggle" type="button"><svg class="icon icon-globe" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855A7.97 7.97 0 0 0 5.145 4H7.5V1.077zM4.09 4a9.267 9.267 0 0 1 .64-1.539 6.7 6.7 0 0 1 .597-.933A7.025 7.025 0 0 0 2.255 4H4.09zm-.582 3.5c.03-.877.138-1.718.312-2.5H1.674a6.958 6.958 0 0 0-.656 2.5h2.49zM4.847 5a12.5 12.5 0 0 0-.338 2.5H7.5V5H4.847zM8.5 5v2.5h2.99a12.495 12.495 0 0 0-.337-2.5H8.5zM4.51 8.5a12.5 12.5 0 0 0 .337 2.5H7.5V8.5H4.51zm3.99 0V11h2.653c.187-.765.306-1.608.338-2.5H8.5zM5.145 12c.138.386.295.744.468 1.068.552 1.035 1.218 1.65 1.887 1.855V12H5.145zm.182 2.472a6.696 6.696 0 0 1-.597-.933A9.268 9.268 0 0 1 4.09 12H2.255a7.024 7.024 0 0 0 3.072 2.472zM3.82 11a13.652 13.652 0 0 1-.312-2.5h-2.49c.062.89.291 1.733.656 2.5H3.82zm6.853 3.472A7.024 7.024 0 0 0 13.745 12H11.91a9.27 9.27 0 0 1-.64 1.539 6.688 6.688 0 0 1-.597.933zM8.5 12v2.923c.67-.204 1.335-.82 1.887-1.855A7.97 7.97 0 0 0 10.855 12H8.5zm3.68-1h2.146c.365-.767.594-1.61.656-2.5h-2.49a13.65 13.65 0 0 1-.312 2.5zm2.802-3.5a6.959 6.959 0 0 0-.656-2.5H12.18c.174.782.282 1.623.312 2.5h2.49zM11.27 2.461c.247.464.462.98.64 1.539h1.835a7.024 7.024 0 0 0-3.072-2.472c.218.284.418.598.597.933zM10.855 4a7.966 7.966 0 0 0-.468-1.068C9.835 1.897 9.17 1.282 8.5 1.077V4h2.355z"></path></svg><span>中文</span></button><div class="language-dropdown"></div></div></div><div class="nav-controls"><div class="more-menu hidden-mobile"><button class="more-toggle" type="button"><span>更多</span><svg class="icon icon-chevron-down" width="12" height="12" viewBox="0 0 12 12" fill="currentColor" aria-hidden="true" focusable="false"><path d="M6 8.825c-.2 0-.4-.1-.5-.2l-3.3-3.3c-.3-.3-.3-.8 0-1.1s.8-.3 1.1 0l2.7 2.7 2.7-2.7c.3-.3.8-.3 1.1 0s.3.8 0 1.1l-3.3 3.3c-.1.1-.3.2-.5.2z"></path></svg></button><div class="more-dropdown"><ul class="dropdown-list"><li class="dropdown-item"><a class="nav-link" href="../archives/index.html">归档</a></li><li class="dropdown-item"><a class="nav-link" href="../categories/index.html">分类</a></li><li class="dropdown-item"><a class="nav-link" href="../tags/index.html">标签</a></li><li class="dropdown-item"><a class="nav-link" href="../about/index.html">关于</a></li><li class="dropdown-item"><a class="nav-link" href="../sitemap/index.html">领地地图</a></li></ul></div></div><div class="theme-switcher"><button class="theme-toggle" type="button" role="switch" aria-pressed="false" aria-label="切换主题"><div class="theme-icon moon-icon"><svg class="icon icon-moon" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278z"></path></svg></div><div class="theme-icon sun-icon"><svg class="icon icon-sun" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M8 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0 1a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z"></path></svg></div></button></div><details class="mobile-menu-details hidden-desktop"><summary class="hamburger-menu" aria-label="nav.menu"><svg class="icon icon-bars" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5z"></path></svg><span class="menu-text">nav.menu</span></summary><div class="mobile-menu-dropdown"><ul class="mobile-nav-list"><li class="mobile-nav-item"><a class="mobile-nav-link" href="../index.html">首页</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../archives/index.html">归档</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../categories/index.html">分类</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../tags/index.html">标签</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../about/index.html">关于</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../sitemap/index.html">领地地图</a></li></ul></div></details></div></div></div></nav></header><main class="container" id="main-content" tabindex="-1"><div class="post"><article class="post-block h-entry"><div class="post-meta p-author h-card visually-hidden"><img class="author-avatar u-photo" src="../favicon.png" alt="Cytrogen"><span class="p-name">Cytrogen</span><a class="u-url" href="https://cytrogen.icu">https://cytrogen.icu</a></div><a class="post-permalink u-url u-uid visually-hidden" href="https://cytrogen.icu/posts/d011.html">永久链接</a><div class="p-summary visually-hidden"><p>近期在学习 IBM 全栈应用开发微学士课程,故此记录学习笔记。</p></div><div class="visually-hidden"><a class="p-category" href="../categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/">编程笔记</a><a class="p-category" href="../tags/IBM/">IBM</a><a class="p-category" href="../tags/React-js/">React.js</a></div><h1 class="post-title p-name">IBM 全栈开发【4】:React 创建前端应用</h1><div class="post-info"><time class="post-date dt-published" datetime="2024-01-18T05:40:13.000Z">1/18/2024</time><time class="dt-updated visually-hidden" datetime="2026-02-09T17:16:54.717Z"></time></div><div class="post-content e-content"><html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程,故此记录学习笔记。</p>
<span id="more"></span>
<h1 id="1-使用react和es6创建前端应用"><a class="markdownIt-Anchor" href="#1-使用react和es6创建前端应用"></a> 1. 使用 React 和 ES6 创建前端应用</h1>
<h2 id="11-前端框架"><a class="markdownIt-Anchor" href="#11-前端框架"></a> 1.1. 前端框架</h2>
<p>前端框架用于创建可连接服务器的动态客户端应用程序。它们通常是开源项目:</p>
<ul>
<li>Angular</li>
<li>React</li>
<li>Vue</li>
</ul>
<h4 id="111-angular"><a class="markdownIt-Anchor" href="#111-angular"></a> 1.1.1. Angular</h4>
<p>Angular 是一个开源的框架,由谷歌维护。它基于 HTML 和 JavaScript,并且易于实现。</p>
<p>Angular 使用指令来使 HTML 更加动态,所有指令都可用于包含库的 HTML。</p>
<figure class="highlight html"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://ajax.googleapis.com/ajax/libs/angularjs/1.3.16/angular"</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">body</span> <span class="attr">ng-app</span>&gt;</span></span><br><span class="line">        Company Name: <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">ng-model</span>=<span class="string">"comp_name"</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span> <span class="attr">ng-bind</span>=<span class="string">"comp_name"</span>&gt;</span><span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<h4 id="112-vue"><a class="markdownIt-Anchor" href="#112-vue"></a> 1.1.2. Vue</h4>
<p>Vue 是一个开源的前端框架,它使用虚拟 DOM 来实现高性能,HTML 被视为一个完整的对象。Vue 非常轻量级、渲染速度快、易于学习。</p>
<figure class="highlight html"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">title</span>&gt;</span>VueJS Introduction<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://cdn.jsdelivr.net/.../vue.js"</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"intro"</span> <span class="attr">style</span>=<span class="string">"text-align: center;"</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">h5</span>&gt;</span></span><br><span class="line">                {{ message }}</span><br><span class="line">            <span class="tag">&lt;/<span class="name">h5</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">        	<span class="keyword">var</span> vue_det = <span class="keyword">new</span> <span class="title class_">Vue</span>({</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">el</span>: <span class="string">"#intro"</span>,</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">data</span>: {</span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">message</span>: <span class="string">"This is a Vue HTML"</span></span></span><br><span class="line"><span class="language-javascript">                }</span></span><br><span class="line"><span class="language-javascript">            });</span></span><br><span class="line"><span class="language-javascript">        </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<h4 id="113-react"><a class="markdownIt-Anchor" href="#113-react"></a> 1.1.3. React</h4>
<p>React 是一个用于构建客户端动态网络应用程序的框架,使用动态数据绑定和虚拟 DOM 来扩展 HTML 语法,而不需要编写额外的代码,并保持用户界面元素与应用程序状态的同步。</p>
<figure class="highlight html"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">h1</span>&gt;</span></span><br><span class="line">            Watson Author Finder</span><br><span class="line">        <span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">p</span>&gt;</span></span><br><span class="line">            Please write your details</span><br><span class="line">        <span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">form</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">id</span>=<span class="string">"name"</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">id</span>=<span class="string">"age"</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>React 使用 JavaScript XML 这种类似于 HTML 的特殊语言来创建用户界面,其可被 Babel 编译器编译为 JavaScript。</p>
<p>JavaScript XML 要嵌入在特殊的脚本标签中,其中的 <code>type</code> 属性指定了需要 Babel 的内容。</p>
<blockquote>
<p>用于构建 React 应用程序的三个重要软件包:</p>
<ul>
<li>React 包:保存组件以及其状态和属性的 React 源代码</li>
<li>ReactDOM 包:React 和 DOM 之间的粘合剂</li>
<li>Babel 编译器:将 JavaScript XML 编译为 JavaScript</li>
</ul>
</blockquote>
<figure class="highlight html"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- Load React API --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://unpkg.com/react@16/umd/react.production.min.js"</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- Load React DOM --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- Load Babel Compiler --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://unpkg.com/babel-standalone@6.15.0/babel.min.js"</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    </span><br><span class="line">    <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"comp1"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/babel"</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">        	<span class="keyword">class</span> <span class="title class_">Mycomp</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span></span><br><span class="line"><span class="language-javascript">        		<span class="comment">// override the render method</span></span></span><br><span class="line"><span class="language-javascript">        		<span class="title function_">render</span>(<span class="params"></span>) {</span></span><br><span class="line"><span class="language-javascript">        			<span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">h1</span>&gt;</span>This is my own component named {this.props.name}<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span>;</span></span><br><span class="line"><span class="language-javascript">        		}</span></span><br><span class="line"><span class="language-javascript">        	}</span></span><br><span class="line"><span class="language-javascript">        	<span class="title class_">ReactDOM</span>.<span class="title function_">render</span>(<span class="language-xml"><span class="tag">&lt;<span class="name">Mycomp</span> <span class="attr">name</span>=<span class="string">"myBrandNewComp"</span>)/&gt;</span></span>, <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">"comp1"</span>));</span></span><br><span class="line"><span class="language-javascript">        </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>React 组件要在 <code>&lt;script&gt;</code> 标签中定义,<code>type</code> 属性的类型需要设置为 <code>text/babel</code>,以便 Babel 编译器将其编译为 JavaScript
<ul>
<li>定义的组件为 <code>Mycomp</code>,继承自 <code>React.Component</code>,并重写了 <code>render()</code> 方法</li>
</ul>
</li>
<li><code>ReactDOM.render()</code> 方法用于渲染组件,并指定组件名称、HTML 标签和要设置的任何属性(该例子中就设置了 <code>name</code> 属性)</li>
<li>组件需要被指定呈现在 HTML 页面的哪个位置(该例子中就是 <code>comp1</code></li>
</ul>
<p>Facebook 提供了一个名为「Create React App」的工具,可以简化创建 React 应用程序的过程。</p>
<p>如果已安装 Node.JS,就可以运行以下命令来安装 Create React App:</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npx create-react-app my-app</span><br></pre></td></tr></tbody></table></figure>
<p>当运行完上述命令后,系统会自动创建一个包含所有必要文件的目录结构。该目录结构包含创建和运行 React 应用程序所需的所有文件。</p>
<ul>
<li><code>src</code> 目录是我们需要修改的主要目录
<ul>
<li><code>App.js</code> 文件是我们要添加到 HTML 页面的 React 根组件</li>
<li><code>index.js</code> 文件将应用程序添加到 HTML 页面</li>
</ul>
</li>
</ul>
<h2 id="12-es6"><a class="markdownIt-Anchor" href="#12-es6"></a> 1.2. ES6</h2>
<p>ES6 的全程为 ECMAScript 6,制定了广泛的全球信息和通信技术标准。</p>
<p>JavaScript 遵循 ECMAScript 6 标准(2015 年),其最主要的更改是:</p>
<ul>
<li><code>let</code></li>
<li><code>const</code></li>
<li>箭头函数</li>
<li>Promise 构造函数</li>
<li></li>
</ul>
<h4 id="121-let和const"><a class="markdownIt-Anchor" href="#121-let和const"></a> 1.2.1. <code>let</code><code>const</code></h4>
<p><code>let/const</code><code>var</code> 不同:</p>
<ul>
<li><code>var</code> 声明的变量的作用域是全局的。这很有挑战性,尤其是在大型项目中,代表着有许多变量需要维护</li>
<li><code>let</code> 可以将变量的作用域限制在声明变量的代码块中 <figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line">    <span class="keyword">let</span> num = <span class="number">5</span>;</span><br><span class="line">    num = <span class="number">6</span>;</span><br><span class="line">}</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num);  <span class="comment">// will throw an error</span></span><br></pre></td></tr></tbody></table></figure>
</li>
<li><code>const</code> 声明的变量的值不能被修改 <figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> num = <span class="number">5</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num);</span><br><span class="line">num = <span class="number">6</span>;  <span class="comment">// will throw an error</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num);</span><br></pre></td></tr></tbody></table></figure>
</li>
</ul>
<h4 id="122-箭头函数"><a class="markdownIt-Anchor" href="#122-箭头函数"></a> 1.2.2. 箭头函数</h4>
<p>箭头函数允许函数像变量一样声明,这是一种更简洁的函数声明方式。</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// how a function was written in the older ES5 JavaScript</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">sayHello</span>(<span class="params"></span>) {</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"ES5 function - Hello world!"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// arrow function in ES6</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">sayHello</span> = (<span class="params"></span>)=&gt; <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"ES6 function - Hello world!"</span>);</span><br></pre></td></tr></tbody></table></figure>
<p>箭头函数可以被调用,并可以作为回调的参数传递。</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">sayHello</span> = (<span class="params"></span>)=&gt; <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"Hello world!"</span>);</span><br><span class="line"><span class="built_in">setTimeout</span>(sayHello, <span class="number">1000</span>);</span><br></pre></td></tr></tbody></table></figure>
<p>箭头函数也可以像普通函数一样接受参数。</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// takes one parameter</span></span><br><span class="line"><span class="comment">// brackets are not mandatory</span></span><br><span class="line"><span class="comment">// because the code returns a value, it must be in curly brackets</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">oneParamArrowFunc</span> = name =&gt; {<span class="keyword">return</span> <span class="string">"hello "</span> + name};</span><br><span class="line"></span><br><span class="line"><span class="comment">// function brackets must be put around the parameters list</span></span><br><span class="line"><span class="comment">// does not need curly brackets because it only has one line of code and returns nothing</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">twoParamsArrowFuncWithoutReturn</span> = (<span class="params">first, last</span>) =&gt; <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"hello "</span> + first + <span class="string">" "</span> + last);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">twoParamsArrowFuncWithReturn</span> = (<span class="params">first, last</span>) =&gt; {<span class="keyword">return</span> <span class="string">"hello "</span> + first + <span class="string">" "</span> + last};</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">twoParamsTwoLinesArrowFunc</span> = (<span class="params">first, last</span>) =&gt; {</span><br><span class="line">    <span class="keyword">const</span> greeting = <span class="string">"hello "</span>;</span><br><span class="line">    <span class="keyword">return</span> greeting + <span class="string">" "</span> + first + <span class="string">" "</span> + last;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<h4 id="123-promise"><a class="markdownIt-Anchor" href="#123-promise"></a> 1.2.3. Promise</h4>
<p>Promise 对象表示了一个异步操作的最终完成或失败,以及其返回值。每当你调用异步操作时,Promise 会处于 pending(挂起)状态;当操作成功地执行时,Promise 会处于 fulfilled(履行)状态;当操作失败时,Promise 会处于 rejected(拒绝)状态。</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="title function_">promiseArgument</span> = (<span class="params">resolve, reject</span>) =&gt; {</span><br><span class="line">    <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> {</span><br><span class="line">        <span class="keyword">let</span> currTime = <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getTime</span>();</span><br><span class="line">        <span class="keyword">if</span> (currTime % <span class="number">2</span> === <span class="number">0</span>) {</span><br><span class="line">            <span class="title function_">resolve</span>(<span class="string">"Success!"</span>);</span><br><span class="line">        } <span class="keyword">else</span> {</span><br><span class="line">            <span class="title function_">reject</span>(<span class="string">"Failed!"</span>);</span><br><span class="line">        }</span><br><span class="line">    }, <span class="number">2000</span>);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> myPromise = <span class="keyword">new</span> <span class="title class_">Promise</span>(promiseArgument);</span><br></pre></td></tr></tbody></table></figure>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> myPromise = <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> {</span><br><span class="line">    <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> {</span><br><span class="line">        <span class="keyword">let</span> currTime = <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getTime</span>();</span><br><span class="line">        <span class="keyword">if</span> (currTime % <span class="number">2</span> === <span class="number">0</span>) {</span><br><span class="line">            <span class="title function_">resolve</span>(<span class="string">"Success!"</span>);</span><br><span class="line">        } <span class="keyword">else</span> {</span><br><span class="line">            <span class="title function_">reject</span>(<span class="string">"Failed!"</span>);</span><br><span class="line">        }</span><br><span class="line">    }, <span class="number">2000</span>);</span><br><span class="line">});</span><br></pre></td></tr></tbody></table></figure>
<blockquote>
<p>以上两种写法是等价的。</p>
</blockquote>
<h4 id="124-类"><a class="markdownIt-Anchor" href="#124-类"></a> 1.2.4. 类</h4>
<p>ES6 中的类使面向对象编程在 JavaScript 中更加容易。类创建了对象的模板,且建立在原型(即 prototype,是所有 JavaScript 对象的属性,包括函数,而函数可用于创建对象实例)的基础上。</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">name, age</span>) {</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">name</span> = name;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">age</span> = age;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> person1 = <span class="title class_">Person</span>(<span class="string">"John"</span>, <span class="number">20</span>);</span><br></pre></td></tr></tbody></table></figure>
<ul>
<li><code>this</code> 指代的是当前对象</li>
<li>类的概念是在函数原型的前提下建立的,目的是将面向对象编程扩展到 JavaScript 中</li>
</ul>
<p>构造函数(constructor)是一个特殊的函数,用于创建一个类对象:</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Rectangle</span> {</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">height, width</span>) {</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">height</span> = height;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">width</span> = width;</span><br><span class="line">    }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> myRectangle = <span class="keyword">new</span> <span class="title class_">Rectangle</span>(<span class="number">10</span>, <span class="number">5</span>);</span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>使用 <code>new</code> 关键字就可以创建一个类的实例</li>
</ul>
<p>在 JavaScript ES6 中,类可以继承自其他类。继承其他类的类被称为子类(subclass),而超类(superclass)是被子类继承的类。子类会继承超类的所有属性和方法。</p>
<p>子类具有特殊权限,能够使用 <code>super()</code> 方法来调用超类的构造函数。</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Square</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Rectangle</span> {</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">height, width</span>) {</span><br><span class="line">        <span class="keyword">if</span> (height === width) {</span><br><span class="line">            <span class="variable language_">super</span>(height, width);</span><br><span class="line">        } <span class="keyword">else</span> {</span><br><span class="line">            <span class="comment">// if the height is not the same as the width specified,</span></span><br><span class="line">            <span class="comment">// the width will become equal to the height</span></span><br><span class="line">            <span class="variable language_">super</span>(height, height);</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> mySquare = <span class="keyword">new</span> <span class="title class_">Square</span>(<span class="number">5</span>, <span class="number">5</span>);</span><br></pre></td></tr></tbody></table></figure>
<h2 id="13-jsx"><a class="markdownIt-Anchor" href="#13-jsx"></a> 1.3. JSX</h2>
<p>JSX 是 JavaScript XML 或 JavaScript Syntax Extension 的缩写,是一种类似于 React 使用的 XML 或 HTML 类语法,用于创建 React 元素。 JSX 允许 XML 或 HTML 类文本与 JavaScript 或 React 代码并存。</p>
<p>JSX 使用预处理器将 JavaScript 文件中的 HTML 类文本转换为标准的 JavaScript 对象,例如转译器或编译器(比方说 Babel)。</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> el1 = <span class="language-xml"><span class="tag">&lt;<span class="name">h1</span>&gt;</span>This is a sample JSX code snippet<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span></span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>JSX 代码的语法就像是 HTML 使用了类似 JavaScript 的变量</li>
</ul>
<h4 id="131-react代码例子"><a class="markdownIt-Anchor" href="#131-react代码例子"></a> 1.3.1. React 代码例子</h4>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">App</span> (<span class="params"></span>) {</span><br><span class="line">    <span class="keyword">return</span> (</span><br><span class="line">    	<span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        	<span class="tag">&lt;<span class="name">p</span>&gt;</span>This is a sample list<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;<span class="name">ul</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            	<span class="tag">&lt;<span class="name">li</span>&gt;</span>List item no. 1<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;<span class="name">li</span>&gt;</span>List item no. 2<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    );</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>而这是普通的 JavaScript 代码:</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">App</span> (<span class="params"></span>) {</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">React</span>.<span class="title function_">createElement</span>(</span><br><span class="line">    	<span class="string">"div"</span>,</span><br><span class="line">        <span class="literal">null</span>,</span><br><span class="line">        <span class="title class_">React</span>.<span class="title function_">createElement</span>(<span class="string">"p"</span>, <span class="literal">null</span>, <span class="string">"This is a sample list"</span>),</span><br><span class="line">        <span class="title class_">React</span>.<span class="title function_">createElement</span>(<span class="string">"ul"</span>, <span class="literal">null</span>,</span><br><span class="line">            <span class="title class_">React</span>.<span class="title function_">createElement</span>(<span class="string">"li"</span>, <span class="literal">null</span>, <span class="string">"List item no. 1"</span>),</span><br><span class="line">                <span class="title class_">React</span>.<span class="title function_">createElement</span>(<span class="string">"li"</span>, <span class="literal">null</span>, <span class="string">"List item no. 2"</span>))</span><br><span class="line">    );</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>可以看出来,如果没有 JSX,React 代码将不得不使用大量嵌套来编写,这会导致代码变得难以阅读和维护。</p>
<h4 id="132-组件"><a class="markdownIt-Anchor" href="#132-组件"></a> 1.3.2. 组件</h4>
<p>组件(component)是 React 的核心构件,是一个可重用的代码块,用于创建用户界面。组件可以是函数或类,它们接受输入并返回 React 元素。</p>
<p>组件可以拥有自己的状态,这些状态是描述了组件行为的对象。有状态的组件的类型为类,而无状态的组件的类型为函数。</p>
<p>React 组件通过三个概念实现这些功能:</p>
<ol>
<li>属性(property):用于从父组件向子组件传递数据</li>
<li>事件(event):使组件能够管理 DOM 事件和用户在系统上交互的动作</li>
<li>状态(state):根据组件的当前状态更新用户界面</li>
</ol>
<p>React 应用程序是一颗组件树:根组件就像一个容器,它包含了所有其他组件。 所有组件的名称,无论是函数还是类,都必须以大写字母开头。组件可以通过使用 <code>className</code> 属性和 CSS 来进行样式化。</p>
<p>组件类型:</p>
<ol>
<li>
<p>函数式组件通过编写 JavaScript 函数来创建,可以接受也可以不接受数据作为参数,返回 JSX 函数。它们本身没有状态或生命周期方法,因此也被称为无状态组件,但是可以通过实现 React Hooks 来添加这些功能。</p>
<ul>
<li>React Hook 是 React 的一项新功能,它能让你在不编写类的情况下使用 React 的特性</li>
<li>生命周期方法(lifecycle methods)是 React 内置的方法,可以在 DOM 中的整个持续时间内对组件进行操作</li>
</ul>
<p>函数式组件用于显示易于阅读、调试和测试的静态数据。</p>
 <figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">Democomponent</span> = (<span class="params"></span>) =&gt; {</span><br><span class="line">    <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">h1</span>&gt;</span>welcome Message!<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>当组件有属性但生命周期不需要管理时最有用。</p>
<p>函数式组件可以接受用户自定义的属性作为参数:</p>
 <figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">App</span>(<span class="params">props</span>) {  <span class="comment">// props passed as a function parameter</span></span><br><span class="line">    <span class="keyword">const</span> compStyle = {</span><br><span class="line">        <span class="attr">color</span>: props.<span class="property">color</span>,</span><br><span class="line">        <span class="attr">fontSize</span>: props.<span class="property">size</span> + <span class="string">'px'</span></span><br><span class="line">    };</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> (</span><br><span class="line">        <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;<span class="name">span</span> <span class="attr">style</span>=<span class="string">{compStyle}</span>&gt;</span>I am a sentence.<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    );</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">App</span>;</span><br></pre></td></tr></tbody></table></figure>
 <figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">ReactDOM</span>.<span class="title function_">render</span>(</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">React.StrictMode</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;<span class="name">App</span> <span class="attr">color</span>=<span class="string">"blue"</span> <span class="attr">size</span>=<span class="string">"25"</span>/&gt;</span>  <span class="comment">&lt;!-- props being sent to the component --&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/<span class="name">React.StrictMode</span>&gt;</span></span>,</span><br><span class="line">    <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'root'</span>)</span><br><span class="line">);</span><br></pre></td></tr></tbody></table></figure>
<p>事件处理程序(event handler)可以通过属性来设置,其中 <code>onClick</code> 处理程序在功能组件中使用的最多:</p>
 <figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="title class_">ReactDOM</span> <span class="keyword">from</span> <span class="string">'react-dom'</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="title class_">App</span> <span class="keyword">from</span> <span class="string">'./App'</span>;</span><br><span class="line"></span><br><span class="line"><span class="title class_">ReactDOM</span>.<span class="title function_">render</span>(</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">React.StrictMode</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;<span class="name">App</span> <span class="attr">color</span>=<span class="string">"blue"</span> <span class="attr">size</span>=<span class="string">"25"</span> <span class="attr">clickEvent</span>=<span class="string">{</span>  &lt;!<span class="attr">--</span> <span class="attr">setting</span> <span class="attr">an</span> <span class="attr">event</span> <span class="attr">handler</span> <span class="attr">method</span> <span class="attr">as</span> <span class="attr">a</span> <span class="attr">property</span> <span class="attr">--</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                () =&gt; { alert("You clicked me!") }</span></span><br><span class="line"><span class="language-xml">            }/&gt;</span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/<span class="name">React.StrictMode</span>&gt;</span></span>,</span><br><span class="line">    <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'root'</span>)</span><br><span class="line">);</span><br></pre></td></tr></tbody></table></figure>
 <figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">App</span>(<span class="params">props</span>) {</span><br><span class="line">    <span class="keyword">return</span> (</span><br><span class="line">        <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{props.clickEvent}</span>&gt;</span>Click Me!<span class="tag">&lt;/<span class="name">button</span>&gt;</span>  <span class="comment">&lt;!-- setting an event handler from props --&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    );</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">App</span>;</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>类组件要比函数式组件更复杂,它们可以将数据传递给其他类组件、可以被 JavaScript ES6 的类创建、可以使用状态、属性和生命周期方法等 React 功能。</p>
 <figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Democomponent</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line">    <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">h1</span>&gt;</span>Welcome Message!<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span>;</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>由于其多功能性,类组件要比函数式组件更受青睐。由于它们继承了 <code>React.Component</code>,因此必须要覆盖 <code>render()</code> 方法。</p>
 <figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// import the React module from the react package</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// create the App class that extends React.Component</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">props</span>) {</span><br><span class="line">        <span class="variable language_">super</span>(props)</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// override the render method</span></span><br><span class="line">    <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{this.props.clickEvent}</span>&gt;</span>Click Me!<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span>;</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">App</span>;</span><br></pre></td></tr></tbody></table></figure>
<p><code>props</code> 在类组件外部设置,而状态要在类组件内部设置:</p>
 <figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">Reach</span> <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">props</span>) {</span><br><span class="line">        <span class="variable language_">super</span>(props)</span><br><span class="line">    }</span><br><span class="line">    state = {<span class="attr">counter</span>: <span class="string">"0"</span>};  <span class="comment">// define the state counter of the component App</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// a function to increment the counter every time a button is clicked</span></span><br><span class="line">    incrementCounter = <span class="function">() =&gt;</span> {</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">counter</span>: <span class="built_in">parseInt</span>(<span class="variable language_">this</span>.<span class="property">state</span>.<span class="property">counter</span>) + <span class="number">1</span>});</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// override the render method</span></span><br><span class="line">    <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{this.incrementCounter}</span>&gt;</span>Click Me!<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;<span class="name">br</span>/&gt;</span></span></span><br><span class="line"><span class="language-xml">            {this.state.counter}</span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>纯组件(pure component)优于函数式组件,主要用于提供优化。它们是编写起来最简单最快的组件,不依赖于其作用域之外的任何变量状态,可以用来替代简单的函数式组件。</p>
</li>
<li>
<p>高阶组件(higher-order component)是 React 中重用组件逻辑的高级技术。API 不提供高阶组件。它们返回组件的函数,用于与其他组件共享逻辑。</p>
 <figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// import React and React Native's Text Core Component</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">Text</span> } <span class="keyword">from</span> <span class="string">'react-native'</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// define a component as a function</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">Helloworld</span> = (<span class="params"></span>) =&gt; {</span><br><span class="line">    <span class="keyword">return</span> (</span><br><span class="line">        <span class="language-xml"><span class="tag">&lt;<span class="name">Text</span>&gt;</span>Hello, World!<span class="tag">&lt;/<span class="name">Text</span>&gt;</span></span></span><br><span class="line">    );</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// export your function component</span></span><br><span class="line"><span class="comment">// the function can then be imported in any application</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">Helloworld</span>;</span><br></pre></td></tr></tbody></table></figure>
</li>
</ol>
<h1 id="2-react组件"><a class="markdownIt-Anchor" href="#2-react组件"></a> 2. React 组件</h1>
<h2 id="21-状态"><a class="markdownIt-Anchor" href="#21-状态"></a> 2.1. 状态</h2>
<p>状态允许你在一个应用程序中修改数据。它被定义为一个对象,使用键值对来存储数据,并帮助你跟踪应用程序中不同类型的数据。</p>
<p>React 组件有一个内置的状态对象,可以在状态对象中存储属于组件的属性值。当状态对象发生变化时,组件会重新渲染。</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// component</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">TestComponent</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.component</span> {</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">state</span> = {</span><br><span class="line">            <span class="attr">id</span>: <span class="number">1</span>,</span><br><span class="line">            <span class="attr">name</span>: <span class="string">"John"</span>,</span><br><span class="line">            <span class="attr">age</span>: <span class="number">28</span></span><br><span class="line">        };</span><br><span class="line">    }</span><br><span class="line">    <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="keyword">return</span> (</span><br><span class="line">        	<span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            	<span class="tag">&lt;<span class="name">p</span>&gt;</span>{ this.state.name }<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;<span class="name">p</span>&gt;</span>{ this.state.age }<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">        )</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>本代码示例展示出了如何创建一个测试组件,该组件包含 <code>id</code><code>name</code><code>age</code> 三个状态属性</li>
<li>组件的 <code>render()</code> 方法返回了状态属性的值</li>
<li>包含属性的状态将根据组件的要求进行更改</li>
</ul>
<p>React 状态的类型:</p>
<ol>
<li>共享状态(shared state):由多个组件共享,比较复杂。例如订单应用程序中的所有订单列表</li>
<li>本地状态(local state):存在于单个组件中,不用于其他组件。例如隐藏和显示信息</li>
</ol>
<h2 id="22-属性"><a class="markdownIt-Anchor" href="#22-属性"></a> 2.2. 属性</h2>
<p>属性用于在 React 组件之间传递数据。工作方式与 HTML 属性类似,它们存储标签的属性值。</p>
<blockquote>
<p>React 组件之间的数据流是从父组件到子组件的单向数据流。</p>
</blockquote>
<p>属性可以像函数参数一样被传递,但它们是只读的,不能在组件内部更改。属性允许子组件访问父组件中被定义的方法(状态则是由父组件管理,而子组件没有自己的状态),大部分组件将根据接收到的属性来显示信息,并保持无状态。</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// component</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">TestComponent</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.component</span> {</span><br><span class="line">    <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span>Hi { this.props.name }<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// passing the props as examples to the text component</span></span><br><span class="line">&lt;<span class="title class_">TestComponent</span> name=<span class="string">"John"</span> /&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">TestComponent</span> <span class="attr">name</span>=<span class="string">"Jill"</span> /&gt;</span></span></span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>该代码示例创建了一个类 <code>TestComponent</code>,该类扩展了 React 组件</li>
</ul>
<h2 id="23-组件阶段"><a class="markdownIt-Anchor" href="#23-组件阶段"></a> 2.3. 组件阶段</h2>
<p>每个 React 组件在其生命周期中都有三个阶段:</p>
<ol>
<li>
<p>挂载阶段(mounting phase):组件被创建并插入 DOM 中。当组件被创建时,会有四个方法被依次调用:</p>
<ol>
<li><code>constructor()</code>:用于初始化组件的状态和属性</li>
<li><code>getDerivedStateFromProps()</code>:用于更新组件的状态</li>
<li><code>render()</code>:用于渲染组件;必须且只能返回一个 DOM 元素</li>
<li><code>componentDidMount()</code>:用于在组件被插入 DOM 后执行一些操作</li>
</ol>
 <figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line">  <span class="comment">// when the component App is created, the constructor is invoked</span></span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">props</span>) {</span><br><span class="line">    <span class="variable language_">super</span>(props)</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"Inside the constructor"</span>)</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  <span class="comment">// the componentDidMount method is invoked</span></span><br><span class="line">  componentDidMount = <span class="function">() =&gt;</span> {</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"Inside component did mount"</span>)</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  <span class="comment">// the render method is invoked</span></span><br><span class="line">  <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"Inside render method"</span>)</span><br><span class="line">    <span class="keyword">return</span> (</span><br><span class="line">            <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">              The component is rendered</span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    );</span><br><span class="line">  }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">App</span>;</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>更新阶段(updating phase):组件的状态或属性发生变化时,会触发更新阶段。当组件更新时,会有五个方法被依次调用:</p>
<ol>
<li><code>getDerivedStateFromProps()</code>:用于更新组件的状态</li>
<li><code>shouldComponentUpdate()</code>:每当状态发生变化时被调用;默认返回 <code>true</code>;应当仅在不想渲染状态的变化时返回 <code>false</code></li>
<li><code>render()</code>:用于渲染组件;必须且只能返回一个 DOM 元素</li>
<li><code>getSnapshotBeforeUpdate()</code>:用于在 DOM 更新前获取 DOM 状态</li>
<li><code>componentDidUpdate()</code>:用于在 DOM 更新后执行一些操作</li>
</ol>
 <figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line">    state = {<span class="attr">counter</span>: <span class="string">"0"</span>};</span><br><span class="line">    </span><br><span class="line">    incrementCounter = <span class="function">() =&gt;</span> <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">counter</span>: <span class="built_in">parseInt</span>(<span class="variable language_">this</span>.<span class="property">state</span>.<span class="property">counter</span>) + <span class="number">1</span>});</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// returns true by default</span></span><br><span class="line">    <span class="comment">// its behavior is rarely changed</span></span><br><span class="line">    <span class="title function_">shouldComponentUpdate</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'Inside shouldComponentUpdate'</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="title function_">getSnapshotBeforeUpdate</span>(<span class="params">prevProps, prevState</span>) {</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'Inside getSnapshotBeforeUpdate'</span>);</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'Prev counter is '</span> + prevState.<span class="property">counter</span>);</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'New counter is '</span> + <span class="variable language_">this</span>.<span class="property">state</span>.<span class="property">counter</span>);</span><br><span class="line">        <span class="keyword">return</span> prevState;</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="title function_">componentDidUpdate</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'Inside componentDidUpdate'</span>)</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// logs on to the console and then renders the component</span></span><br><span class="line">    <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'Inside render'</span>)</span><br><span class="line">        <span class="keyword">return</span> (</span><br><span class="line">            <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="comment">&lt;!-- With the onClick of the button, incrementCounter is invoked, increasing the counter state by 1 --&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{this.incrementCounter}</span>&gt;</span>Click Me!<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                {this.state.counter}</span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">        );</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">App</span>;</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>卸载阶段(unmounting phase):组件从 DOM 中移除时,会触发卸载阶段。当组件被卸载时,会有一个方法被调用:</p>
<ol>
<li><code>componentWillUnmount()</code>:用于在组件被卸载前执行一些操作</li>
</ol>
 <figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">AppInner</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line">    <span class="title function_">componentWillUnmount</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'This component will unmount'</span>)</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span>Inner component<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line">    state = {<span class="attr">innerComponent</span>:<span class="language-xml"><span class="tag">&lt;<span class="name">AppInner</span>/&gt;</span></span>}</span><br><span class="line">    </span><br><span class="line">    <span class="title function_">componentDidMount</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> {</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">innerComponent</span>: <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span>unmounted<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span>})    </span><br><span class="line">        }, <span class="number">5000</span>)</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'Inside render'</span>)</span><br><span class="line">        <span class="keyword">return</span> (</span><br><span class="line">            <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                {this.state.innerComponent}</span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">        );</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">App</span>;</span><br></pre></td></tr></tbody></table></figure>
</li>
</ol>
<h2 id="24-组件之间的数据传递"><a class="markdownIt-Anchor" href="#24-组件之间的数据传递"></a> 2.4. 组件之间的数据传递</h2>
<p>React 组件之间的数据传递可以有:</p>
<ol>
<li>使用属性的「父到子」数据传递</li>
<li>使用回调函数的「子到父」数据传递</li>
<li>使用 Redux 的「兄弟」数据传递(此处不做讨论)</li>
</ol>
<p>父到子:</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line">    state = {<span class="attr">childColor</span>: <span class="string">"green"</span>, <span class="attr">name</span>: <span class="string">"John"</span>}</span><br><span class="line">    </span><br><span class="line">    changeColor = <span class="function">() =&gt;</span> {</span><br><span class="line">        <span class="keyword">const</span> newcolor = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'colorbox'</span>).<span class="property">value</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">childColor</span>: newcolor})</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    changeName = <span class="function">() =&gt;</span> {</span><br><span class="line">        <span class="keyword">const</span> newname = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'namebox'</span>).<span class="property">value</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">name</span>: newname})</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'Inside render'</span>)</span><br><span class="line">        <span class="keyword">return</span> (</span><br><span class="line">        	<span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            	Color <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"Text"</span> <span class="attr">onChange</span>=<span class="string">{this.changeColor}</span> <span class="attr">id</span>=<span class="string">"colorbox"</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;<span class="name">br</span>/&gt;</span></span></span><br><span class="line"><span class="language-xml">                Name <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"Text"</span> <span class="attr">onChange</span>=<span class="string">{this.changeName}</span> <span class="attr">id</span>=<span class="string">"namebox"</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">                </span></span><br><span class="line"><span class="language-xml">                <span class="comment">&lt;!-- App sets the property color and name for AppInner --&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="comment">&lt;!-- The data is passed to the child every time a new value is entered in the input boxes in the parent --&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;<span class="name">AppInner</span> <span class="attr">color</span>=<span class="string">{this.state.childColor}</span> <span class="attr">name</span>=<span class="string">{this.state.name}</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">        );</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">AppInner</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">props</span>) {</span><br><span class="line">        <span class="variable language_">super</span>(props)</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="keyword">const</span> txtStyle = {<span class="attr">color</span>: <span class="variable language_">this</span>.<span class="property">props</span>.<span class="property">color</span>}</span><br><span class="line">        <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">span</span> <span class="attr">style</span>=<span class="string">{txtStyle}</span>&gt;</span>{this.props.name}<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>其中,<code>App</code> 组件是 <code>AppInner</code> 组件的父组件</li>
</ul>
<p>子到父:</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line">    state = {<span class="attr">message</span>: <span class="string">""</span>}</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// Func1 is a parent component function which takes a string argument</span></span><br><span class="line">    func1 = <span class="function">(<span class="params">childData</span>) =&gt;</span> {</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">message</span>: childData})</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="keyword">return</span> (</span><br><span class="line">        	<span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="comment">&lt;!-- Pass the callback func1 as a property to the child --&gt;</span></span></span><br><span class="line"><span class="language-xml">            	<span class="tag">&lt;<span class="name">AppInner</span> <span class="attr">parentCallback</span> = <span class="string">{this.func1}</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;<span class="name">p</span>&gt;</span>{this.state.message}<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">        );</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">AppInner</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line">    sendData = <span class="function">() =&gt;</span> {</span><br><span class="line">        <span class="built_in">setInterval</span>(<span class="function">() =&gt;</span> {</span><br><span class="line">            <span class="keyword">const</span> currTime = <span class="title class_">Date</span>();</span><br><span class="line">            <span class="comment">// the parent class method which sets the state of the parent component</span></span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">props</span>.<span class="title function_">parentCallback</span>(currTime);</span><br><span class="line">        }, <span class="number">1000</span>);</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// invoke the sendData method</span></span><br><span class="line">    <span class="title function_">componentDidMount</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">sendData</span>();</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<h2 id="25-组件的生命周期"><a class="markdownIt-Anchor" href="#25-组件的生命周期"></a> 2.5. 组件的生命周期</h2>
<p>组件的生命周期代表了组件从创建到销毁的整个过程。React 组件的生命周期包含四个阶段,每个阶段都有不同的方法:</p>
<ol>
<li>初始化(initialization):组件以给定的属性和默认状态被创建</li>
<li>挂载(mounting):渲染由 <code>render()</code> 方法返回的 JSX</li>
<li>更新(updating):当组件的状态或属性发生变化时,会触发更新阶段</li>
<li>卸载(unmounting):组件从 DOM 中移除</li>
</ol>
<h4 id="251-挂载阶段"><a class="markdownIt-Anchor" href="#251-挂载阶段"></a> 2.5.1. 挂载阶段</h4>
<p>挂载阶段中,组件被添加到 DOM,并在组件加载前和加载后调用两个预定义方法:</p>
<ol>
<li><code>componentWillMount()</code></li>
<li><code>componentDidMount()</code></li>
</ol>
<h4 id="252-更新阶段"><a class="markdownIt-Anchor" href="#252-更新阶段"></a> 2.5.2. 更新阶段</h4>
<p>组件的状态或属性发生变化时,会触发更新阶段。变化可以在组件内发生,也可以通过后台发生,这些变化都会触发 <code>render()</code> 方法的调用。</p>
<ol>
<li><code>getDerivedStateFromProps()</code></li>
<li><code>shouldComponentUpdate()</code></li>
<li><code>render()</code></li>
<li><code>getSnapshotBeforeUpdate()</code></li>
<li><code>componentDidUpdate()</code></li>
</ol>
<h4 id="253-卸载阶段"><a class="markdownIt-Anchor" href="#253-卸载阶段"></a> 2.5.3. 卸载阶段</h4>
<p>组件从 DOM 中移除时,会触发卸载阶段。在卸载阶段,只有一个方法被调用:</p>
<ol>
<li><code>componentWillUnmount()</code></li>
</ol>
<h2 id="26-外部服务"><a class="markdownIt-Anchor" href="#26-外部服务"></a> 2.6. 外部服务</h2>
<p>路由器(router)可以连接到外部服务以执行多种操作,例如:</p>
<ol>
<li>
<p><code>GET</code>:从服务器获取数据</p>
 <figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line">    state = {</span><br><span class="line">        <span class="attr">user</span>: <span class="string">"None Logged In"</span></span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// connect to a server through an axios request</span></span><br><span class="line">    <span class="title function_">componentDidMount</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="keyword">const</span> req = axios.<span class="title function_">get</span>(<span class="string">"&lt;external server&gt;"</span>);</span><br><span class="line">        req.<span class="title function_">then</span>(<span class="function"><span class="params">resp</span> =&gt;</span> {</span><br><span class="line">            <span class="comment">// then the promise is fulfilled, you parse the response and extract the data from it to change user to have the same name as its value</span></span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">user</span>: resp.<span class="property">data</span>.<span class="property">name</span>});</span><br><span class="line">        })</span><br><span class="line">        .<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> {</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">user</span>: <span class="string">"Invalid user"</span>});</span><br><span class="line">        });</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="keyword">return</span> (</span><br><span class="line">            <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                Current user - {this.state.user}</span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">        );</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p><code>POST</code>:将数据发送到服务器</p>
 <figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">"express"</span>);</span><br><span class="line"><span class="keyword">const</span> app = <span class="keyword">new</span> <span class="title function_">express</span>();</span><br><span class="line"></span><br><span class="line"><span class="comment">// this server uses the CORS middleware to allow cross-origin requests to the server</span></span><br><span class="line"><span class="keyword">const</span> cors_app = <span class="built_in">require</span>(<span class="string">"cors"</span>);</span><br><span class="line">app.<span class="title function_">use</span>(<span class="title function_">cors_app</span>());</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> usercollection = [];</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">"/user"</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> {</span><br><span class="line">    <span class="keyword">let</span> newuser = {<span class="string">"name"</span>: req.<span class="property">query</span>.<span class="property">name</span>, <span class="string">"gender"</span>: req.<span class="property">query</span>.<span class="property">gender</span>}</span><br><span class="line">    usercollection.<span class="title function_">push</span>(newuser);</span><br><span class="line">    <span class="keyword">return</span> res.<span class="title function_">send</span>(<span class="string">"User successfully added"</span>);</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">"/user"</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> {</span><br><span class="line">    <span class="keyword">return</span> res.<span class="title function_">send</span>(usercollection);</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">3333</span>, <span class="function">() =&gt;</span> {</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"Listening at http://localhost:3333"</span>)</span><br><span class="line">})</span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>Express 服务器接收端点 <code>/user</code><code>POST</code> 请求,并将数据存储在 <code>usercollection</code> 数组中</li>
</ul>
 <figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line">    state = {<span class="attr">completionstatus</span>: <span class="string">""</span>}</span><br><span class="line">    </span><br><span class="line">    postDataToServer = <span class="function">() =&gt;</span> {</span><br><span class="line">        axios.<span class="title function_">post</span>(<span class="string">"http://localhost:3333/user?name="</span> +</span><br><span class="line">                   <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">"name"</span>).<span class="property">value</span> +</span><br><span class="line">                  <span class="string">"&amp;gender="</span> + <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">"gender"</span>).<span class="property">value</span></span><br><span class="line">        )</span><br><span class="line">        .<span class="title function_">then</span>(<span class="function"><span class="params">response</span> =&gt;</span> {</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">completionstatus</span>: response.<span class="property">data</span>})</span><br><span class="line">        }).<span class="title function_">catch</span>(<span class="function">(<span class="params">err</span>) =&gt;</span> {</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">setState</span>({<span class="attr">completionstatus</span>: <span class="string">"Operation failure"</span>})</span><br><span class="line">        })</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="keyword">return</span> (</span><br><span class="line">            <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                Enter the name <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">id</span>=<span class="string">"name"</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;<span class="name">br</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">                Enter the gender <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">id</span>=<span class="string">"gender"</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;<span class="name">br</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{this.postDataToServer}</span>&gt;</span>Post Data<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;<span class="name">span</span>&gt;</span>{this.state.completionstatus}<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">        );</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p><code>UPDATE</code>:修改数据</p>
</li>
<li>
<p><code>DELETE</code>:删除数据</p>
</li>
</ol>
<p>大多数对外部服务器的请求都是阻塞性的。要异步调用,可以使用 Promise。</p>
<h2 id="27-测试"><a class="markdownIt-Anchor" href="#27-测试"></a> 2.7. 测试</h2>
<p>测试可以是一套由代码组成的,以验证应用程序的无差错执行。</p>
<p>测试 React 组件有多个好处:验证代码运行无误;通过复制最终用户的行为来测试组件;通过测试组件的不同状态来测试组件;防止先前已修复的错误再次出现。</p>
<p>测试有着两种类型:</p>
<ol>
<li>在简单的测试环境中渲染组件树并验证其输出</li>
<li>在真实的浏览器环境中运行应用程序,进行端到端的测试</li>
</ol>
<h4 id="271-react组件测试的阶段"><a class="markdownIt-Anchor" href="#271-react组件测试的阶段"></a> 2.7.1. React 组件测试的阶段</h4>
<ol>
<li>安排(arrange):组件需要将其 DOM 渲染到用户界面</li>
<li>操作(act):注册任何可能以编程方法触发的用户行为</li>
<li>断言(assert):验证组件的输出是否与预期的输出相匹配</li>
</ol>
<h4 id="272-测试工具"><a class="markdownIt-Anchor" href="#272-测试工具"></a> 2.7.2. 测试工具</h4>
<p>速度 vs 环境:</p>
<ul>
<li>有些工具能在做出修改和看到结果之间提供非常快的回馈,但无法精确地模拟浏览器行为</li>
<li>有些工具可能会使用真实的浏览器环境,但会降低迭代速度,在持续集成环境中使用时可能会导致不稳定</li>
</ul>
<p>测试工具有:</p>
<ul>
<li>Mocha</li>
<li>Chai:断言库</li>
<li>Sinon</li>
<li>Enzyme:渲染组件</li>
<li>Jest:测试 React 组件,并拥有着 Mocha、Chai、Sinon 以及其他工具的能力</li>
<li>React Testing Library:测试 React 组件</li>
</ul>
<h1 id="3-react进阶"><a class="markdownIt-Anchor" href="#3-react进阶"></a> 3. React 进阶</h1>
<h2 id="31-hooks"><a class="markdownIt-Anchor" href="#31-hooks"></a> 3.1. Hooks</h2>
<p>Hooks 是在用户界面中封装有状态的行为的更简单的方法,它们允许函数式组件访问状态和其他 React 功能。Hooks 是常规的 JavaScript 函数,提供使用上下文或状态等功能的方法,且无需编写类,帮助你使代码更简洁。</p>
<blockquote>
<p>类组件有时会带来一些问题,例如封装复杂、组件大小难以管理以及类混淆等。</p>
</blockquote>
<p>标准的 Hooks:</p>
<ul>
<li><code>useState</code>:为函数式组件添加状态</li>
<li><code>useEffect</code>:管理副作用(side effects)</li>
<li><code>useContext</code>:管理上下文</li>
<li><code>useReducer</code>:管理 Redux 的状态变化</li>
</ul>
<p>自定义 Hooks 允许你为应用程序添加特殊功能。它们可以由一个或多个 Hooks 组成、可以被重复使用、分解为更小的 Hooks。自定义 Hooks 需要以 <code>use</code> 开头。</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span>, { useState } <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">CntApp</span>(<span class="params"></span>) {</span><br><span class="line">    <span class="comment">// declare a new state variable "count"</span></span><br><span class="line">    <span class="comment">// useState is the hook which needs to call inside a function component to add some local state to it</span></span><br><span class="line">    <span class="keyword">const</span> [count, setCount] = <span class="title function_">useState</span>(<span class="number">0</span>);</span><br><span class="line">    <span class="keyword">return</span> (</span><br><span class="line">    	<span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        	<span class="tag">&lt;<span class="name">p</span>&gt;</span>You clicked {count} many times<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{()</span> =&gt;</span> setCount(count + 1)}&gt;</span></span><br><span class="line"><span class="language-xml">            	Click me</span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    );</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">CntApp</span>;</span><br></pre></td></tr></tbody></table></figure>
<h2 id="32-表单"><a class="markdownIt-Anchor" href="#32-表单"></a> 3.2. 表单</h2>
<p>大多数 React 表单都是单页面应用程序(SPA)或者加载单个页面的网络应用程序。表单使用组件处理数据、使用事件处理程序控制变量的变化和状态的更新。</p>
<p>表单标签有:</p>
<ul>
<li><code>&lt;input&gt;</code></li>
<li><code>&lt;textarea&gt;</code></li>
<li><code>&lt;select&gt;</code></li>
</ul>
<p>在 HTML,状态由表单元素管理;在 React,组件的状态管理着表单元素。</p>
<h4 id="321-输入类型"><a class="markdownIt-Anchor" href="#321-输入类型"></a> 3.2.1. 输入类型</h4>
<table>
<thead>
<tr>
<th>非受控输入</th>
<th>受控输入</th>
</tr>
</thead>
<tbody>
<tr>
<td>允许浏览器处理大部分表单元素,并通过 React 的变化事件收集数据</td>
<td>使用 React 直接设置和更新输入值,从而完全控制元素</td>
</tr>
<tr>
<td>在输入的 DOM 节点中管理自己的状态</td>
<td>函数管理数据的传递</td>
</tr>
<tr>
<td>元素会在输入值发生变化的时候更新</td>
<td>更好地控制表单元素和数据</td>
</tr>
<tr>
<td><code>ref</code> 函数用于从 DOM 中获取表单值</td>
<td>属性获取当前值并通知更改</td>
</tr>
<tr>
<td></td>
<td>父组件控制更改</td>
</tr>
</tbody>
</table>
<p>表单示例:</p>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span>, { <span class="title class_">Component</span> } <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">function</span> <span class="title function_">App</span>(<span class="params"></span>) {</span><br><span class="line">    <span class="comment">// to track the state of the email address, this example uses a hook</span></span><br><span class="line">    <span class="keyword">const</span> [email, setEmail] = <span class="title class_">React</span>.<span class="title function_">useState</span>(<span class="string">""</span>);</span><br><span class="line">    <span class="keyword">const</span> [password, setPassword] = <span class="title class_">React</span>.<span class="title function_">useState</span>(<span class="string">""</span>);</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">handleSubmit</span> = (<span class="params">event</span>) =&gt; {</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"Email: ${email}\nPassword: ${password}"</span>);</span><br><span class="line">        event.<span class="title function_">preventDefault</span>();</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> (</span><br><span class="line">        <span class="language-xml"><span class="tag">&lt;<span class="name">form</span> <span class="attr">onSubmit</span>=<span class="string">{handleSubmit}</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        	<span class="tag">&lt;<span class="name">h1</span>&gt;</span>Registration<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;<span class="name">label</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="comment">&lt;!-- to ensure that the email remains updated when the use interacts with form, you must add as input, value, and onChange attributes to the email address --&gt;</span></span></span><br><span class="line"><span class="language-xml">            	Email: <span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">"email"</span> <span class="attr">type</span>=<span class="string">"email"</span> <span class="attr">value</span>=<span class="string">{email}</span> <span class="attr">onChange</span>=<span class="string">{e</span> =&gt;</span> setEmail(e.target.value)} required /&gt;</span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;/<span class="name">label</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;<span class="name">label</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            	Password: <span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">"password"</span> <span class="attr">type</span>=<span class="string">"password"</span> <span class="attr">value</span>=<span class="string">{password}</span> <span class="attr">onChange</span>=<span class="string">{e</span> =&gt;</span> setPassword(e.target.value)} required /&gt;</span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;/<span class="name">label</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            </span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;<span class="name">button</span>&gt;</span>Submit<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span></span><br><span class="line">    );</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<blockquote>
<p>React Hook Form 是一个创建表单的实用软件包,它可以帮助你创建可重用的表单组件。</p>
</blockquote>
<h2 id="33-redux"><a class="markdownIt-Anchor" href="#33-redux"></a> 3.3. Redux</h2>
<p>Redux 是一个状态管理库,它遵循一种称为 Flux 架构的模式,通常在组件数量较多的时候实用。</p>
<p>Redux 提供了一个集中的状态管理系统,它将应用程序的所有状态存储在一个单一的对象中,称为存储(store)。存储是一个 JavaScript 对象,它包含了应用程序的所有状态。</p>
<p>Redux 的工作流程:当用户与应用程序的某个组件交互时,<code>Action</code> 会更新整个应用程序的状态,这反过来又会触发组件的重新渲染,从而更新该组件的属性,这些属性会将结果反馈给用户。</p>
<h4 id="331-概念"><a class="markdownIt-Anchor" href="#331-概念"></a> 3.3.1. 概念</h4>
<ol>
<li><code>Action</code>:【你的应用程序能做什么】。它是一个由选择单选按钮、复选框或点击按钮触发的事件 / JSON 对象;它包含着需要对状态进行更改的信息,并由被称为操作创建器(action creator)的函数创建。<code>Action</code> 由应用程序的各个部分派发,并由存储空间接收</li>
<li><code>Store</code>:应用程序状态的唯一位置和权威来源。它是一个包含着状态、函数和其他对象的对象,可以调度和接收操作。<code>Store</code> 的更新能够被订阅</li>
<li><code>Reducers</code>:返回全新的状态的函数。它们从 <code>Store</code> 接收 <code>Action</code>,并对状态进行适当更改。作为事件监听器,<code>Reducer</code> 会读取 <code>Action</code> 的有效载荷(payload)并更新 <code>Store</code><ul>
<li><code>Reducer</code> 接收两个参数:先前的应用程序状态和 <code>Action</code></li>
</ul>
</li>
</ol>
<h4 id="332-中间件"><a class="markdownIt-Anchor" href="#332-中间件"></a> 3.3.2 中间件</h4>
<p>中间件(middleware)是一个函数,它可以访问 <code>Action</code><code>Store</code>,并且可以在 <code>Action</code> 到达 <code>Reducer</code> 之前执行某些操作。它可以用于日志记录、分析、异步请求等。</p>
<ol>
<li>Thunk 中间件:允许在操作创建器中传递函数以创建 <code>async</code> Redux、允许编写操作创建器、允许延迟调度操作、允许调度多个操作。优势是 Thunk 中间件可以无需大量模板代码即可实现异步操作、学习难度小、易于使用;缺点是不能直接对操作做出响应、难以处理可能出现的并发问题、是命令式的、不太容易测试和扩展</li>
<li>Saga 中间件:使用称为生成器(generator)的 ES6 功能来实现异步操作、允许以纯函数的形式表达复杂的逻辑、易于测试、允许分离关注点、易于扩展具有副作用的复杂操作、易于通过 <code>try/catch</code> 处理错误;缺点是不适合简单的应用程序、需要更多的模板代码、需要具备生成器的知识</li>
<li>基于 Promise 的中间件</li>
</ol>
<h4 id="333-数据流"><a class="markdownIt-Anchor" href="#333-数据流"></a> 3.3.3. 数据流</h4>
<p>React-Redux 应用程序的数据流是单向的。它只朝一个方向流动。</p>
<ol>
<li>操作创建器(action creator)朝根归纳器(root reducer)流动</li>
<li>根归纳器处理 <code>Action</code> 并返回新的状态到储存空间(store)</li>
<li>存储空间更新用户界面(UI)</li>
<li>用户界面调用操作创建器</li>
</ol>
<p>为什么要选择单向数据流:双向数据绑定会影响浏览器性能,而且很难跟踪数据流,因此 Redux 的单向数据流解决了这个问题。</p>
</body></html></div></article></div></main><footer><div class="paginator"><a class="prev" href="fed2.html">上一篇</a><a class="next" href="d62.html">下一篇</a></div><!-- Webmention 显示区域--><div class="webmention-section webmention-empty" data-page-url="posts/d011.html" data-full-url="https://cytrogen.icu/posts/d011.html" data-mode="static">
              <h3 class="webmention-title">Webmentions (<span class="webmention-count">0</span>)</h3>
              <div class="webmention-list"></div>
              <span>暂无 Webmentions</span>
            </div><div class="copyright"><p class="footer-links"><a href="../friends/index.html">友链</a><span class="footer-separator"> ·</span><a href="../links/index.html">邻邦</a><span class="footer-separator"> ·</span><a href="../contact/index.html">联络</a><span class="footer-separator"> ·</span><a href="../colophon/index.html">营造记</a><span class="footer-separator"> ·</span><a href="../atom.xml">RSS订阅</a></p><p>© 2025 - 2026 <a href="https://cytrogen.icu">Cytrogen</a>, powered by <a href="https://hexo.io/" target="_blank">Hexo</a> and <a href="https://github.com/cytrogen/hexo-theme-ares" target="_blank">hexo-theme-ares</a>.</p><p><a href="https://blogscn.fun" target="_blank" rel="noopener">BLOGS·CN</a></p></div></footer></div></div><a class="back-to-top" href="#top" aria-label="返回顶部"><svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M3.293 9.707a1 1 0 010-1.414L9.586 2a2 2 0 012.828 0l6.293 6.293a1 1 0 01-1.414 1.414L11 3.414V17a1 1 0 11-2 0V3.414L2.707 9.707a1 1 0 01-1.414 0z"></path></svg></a><script>document.addEventListener('DOMContentLoaded', function() {
  const codeBlocks = document.querySelectorAll('figure.highlight');
  
  codeBlocks.forEach(block => {
    let caption = block.querySelector('figcaption');
    if (!caption) {
      caption = document.createElement('figcaption');
      block.insertBefore(caption, block.firstChild);
    }

    const info = document.createElement('div');
    info.className = 'info';
    
    const filename = caption.querySelector('span');
    if (filename) {
      filename.className = 'filename';
      info.appendChild(filename);
    }
    
    const lang = block.className.split(' ')[1];
    if (lang) {
      const langSpan = document.createElement('span');
      langSpan.className = 'lang-name';
      langSpan.textContent = lang;
      info.appendChild(langSpan);
    }

    const sourceLink = caption.querySelector('a');
    if (sourceLink) {
      sourceLink.className = 'source-link';
      info.appendChild(sourceLink);
    }

    const actions = document.createElement('div');
    actions.className = 'actions';

    const codeHeight = block.scrollHeight;
    const threshold = 300;

    if (codeHeight > threshold) {
      block.classList.add('folded');
      
      const toggleBtn = document.createElement('button');
      toggleBtn.textContent = '展开';
      toggleBtn.addEventListener('click', () => {
        block.classList.toggle('folded');
        toggleBtn.textContent = block.classList.contains('folded') ? '展开' : '折叠';
      });
      actions.appendChild(toggleBtn);
    }

    const copyBtn = document.createElement('button');
    copyBtn.textContent = '复制';
    copyBtn.addEventListener('click', async () => {
      const codeLines = block.querySelectorAll('.code .line');
      const code = Array.from(codeLines)
        .map(line => line.textContent)
        .join('\n')
        .replace(/\n\n/g, '\n');
      
      try {
        await navigator.clipboard.writeText(code);
        copyBtn.textContent = '已复制';
        copyBtn.classList.add('copied');
        
        setTimeout(() => {
          copyBtn.textContent = '复制';
          copyBtn.classList.remove('copied');
        }, 3000);
      } catch (err) {
        console.error('复制失败:', err);
        copyBtn.textContent = '复制失败';
        
        setTimeout(() => {
          copyBtn.textContent = '复制';
        }, 3000);
      }
    });
    actions.appendChild(copyBtn);

    caption.innerHTML = '';
    caption.appendChild(info);
    caption.appendChild(actions);

    const markedLines = block.getAttribute('data-marked-lines');
    if (markedLines) {
      const lines = markedLines.split(',');
      lines.forEach(range => {
        if (range.includes('-')) {
          const [start, end] = range.split('-').map(Number);
          for (let i = start; i <= end; i++) {
            const line = block.querySelector(`.line-${i}`);
            if (line) line.classList.add('marked');
          }
        } else {
          const line = block.querySelector(`.line-${range}`);
          if (line) line.classList.add('marked');
        }
      });
    }
  });
});</script><script async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" id="MathJax-script"></script><script>(function() {
  document.addEventListener('DOMContentLoaded', function() {
    const themeToggle = document.querySelector('.theme-toggle');
    
    if (!themeToggle) return;
    
    const getCurrentTheme = () => {
      return document.documentElement.getAttribute('data-theme') || 'light';
    };
    
    const updateUI = (theme) => {
      const isDark = theme === 'dark';
      themeToggle.setAttribute('aria-pressed', isDark.toString());
    };
    
    const setTheme = (theme) => {
      document.documentElement.setAttribute('data-theme', theme);
      document.documentElement.style.colorScheme = theme;
      
      const pageWrapper = document.getElementById('page-wrapper');
      if (pageWrapper) {
        pageWrapper.setAttribute('data-theme', theme);
      }
      
      // Find and remove the temporary anti-flicker style tag if it exists.
      // This ensures the main stylesheet takes full control after the initial load.
      const antiFlickerStyle = document.getElementById('anti-flicker-style');
      if (antiFlickerStyle) {
        antiFlickerStyle.remove();
      }
      
      localStorage.setItem('theme', theme);
      updateUI(theme);
    };
    
    const toggleTheme = () => {
      const current = getCurrentTheme();
      const newTheme = current === 'light' ? 'dark' : 'light';
      setTheme(newTheme);
    };
    
    updateUI(getCurrentTheme());
    
    themeToggle.addEventListener('click', toggleTheme);
    
    if (window.matchMedia) {
      const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
      mediaQuery.addEventListener('change', function(e) {
        if (!localStorage.getItem('theme')) {
          const theme = e.matches ? 'dark' : 'light';
          setTheme(theme);
        }
      });
    }
  });
})();
</script><script src="../js/details-toggle.js" defer></script><script>(function() {
  document.addEventListener('DOMContentLoaded', function() {
    const backToTopBtn = document.querySelector('.back-to-top');
    
    if (!backToTopBtn) return;
    
    const toggleButtonVisibility = () => {
      const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
      const shouldShow = scrollTop > 200;
      
      if (shouldShow) {
        backToTopBtn.classList.add('is-visible');
      } else {
        backToTopBtn.classList.remove('is-visible');
      }
    };
    
    let ticking = false;
    const handleScroll = () => {
      if (!ticking) {
        requestAnimationFrame(() => {
          toggleButtonVisibility();
          ticking = false;
        });
        ticking = true;
      }
    };
    
    const scrollToTop = (event) => {
      event.preventDefault();
      window.scrollTo({
        top: 0,
        behavior: 'smooth'
      });
    };
    
    window.addEventListener('scroll', handleScroll);
    backToTopBtn.addEventListener('click', scrollToTop);
    
    toggleButtonVisibility();
  });
})();</script></body></html>