-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
1671 lines (650 loc) · 120 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html class="theme-next muse use-motion" lang="zh-Hans">
<head><meta name="generator" content="Hexo 3.9.0">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="theme-color" content="#222">
<meta http-equiv="Cache-Control" content="no-transform">
<meta http-equiv="Cache-Control" content="no-siteapp">
<link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css">
<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css">
<link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css">
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.4">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.4">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.4">
<link rel="mask-icon" href="/images/logo.svg?v=5.1.4" color="#222">
<meta name="keywords" content="Hexo, NexT">
<meta property="og:type" content="website">
<meta property="og:title" content="明天会更好">
<meta property="og:url" content="http://localhost:4000/index.html">
<meta property="og:site_name" content="明天会更好">
<meta property="og:locale" content="zh-Hans">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="明天会更好">
<script type="text/javascript" id="hexo.configurations">
var NexT = window.NexT || {};
var CONFIG = {
root: '/',
scheme: 'Muse',
version: '5.1.4',
sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
fancybox: true,
tabs: true,
motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
duoshuo: {
userId: '0',
author: '博主'
},
algolia: {
applicationID: '',
apiKey: '',
indexName: '',
hits: {"per_page":10},
labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
}
};
</script>
<link rel="canonical" href="http://localhost:4000/">
<title>明天会更好</title>
</head>
<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">
<div class="container sidebar-position-left
page-home">
<div class="headband"></div>
<header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"><div class="site-brand-wrapper">
<div class="site-meta ">
<div class="custom-logo-site-title">
<a href="/" class="brand" rel="start">
<span class="logo-line-before"><i></i></span>
<span class="site-title">明天会更好</span>
<span class="logo-line-after"><i></i></span>
</a>
</div>
<p class="site-subtitle">道阻且长,行则将至</p>
</div>
<div class="site-nav-toggle">
<button>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
</button>
</div>
</div>
<nav class="site-nav">
<ul id="menu" class="menu">
<li class="menu-item menu-item-home">
<a href="/" rel="section">
<i class="menu-item-icon fa fa-fw fa-home"></i> <br>
首页
</a>
</li>
<li class="menu-item menu-item-archives">
<a href="/archives/" rel="section">
<i class="menu-item-icon fa fa-fw fa-archive"></i> <br>
归档
</a>
</li>
</ul>
</nav>
</div>
</header>
<main id="main" class="main">
<div class="main-inner">
<div class="content-wrap">
<div id="content" class="content">
<section id="posts" class="posts-expand">
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://localhost:4000/2020/08/01/ReactHooks实战-2/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="Rex Wang">
<meta itemprop="description" content>
<meta itemprop="image" content="/images/avatar.gif">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="明天会更好">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2020/08/01/ReactHooks实战-2/" itemprop="url">ReactHooks实战-2</a></h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建于" itemprop="dateCreated datePublished" datetime="2020-08-01T12:33:35+08:00">
2020-08-01
</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="自定义-Hooks"><a href="#自定义-Hooks" class="headerlink" title="自定义 Hooks"></a>自定义 Hooks</h1><blockquote>
<p>自定义 Hook 是 React Hooks 中最有趣的功能,或者说特色。简单来说,它用一种高度灵活的方式,能够让你在不同的函数组件之间共享某些特定的逻辑。</p>
</blockquote>
<h2 id="一个简单的自定义-Hooks"><a href="#一个简单的自定义-Hooks" class="headerlink" title="一个简单的自定义 Hooks"></a>一个简单的自定义 Hooks</h2><figure class="highlight bash"><table><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">import { useState, useEffect } from <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line">// 自定义hook useMousePostion</span><br><span class="line">const useMousePostion = () => {</span><br><span class="line"> // 使用hookuseState初始化一个state</span><br><span class="line"> const [postion, setPostion] = useState({ x: 0, y: 0 });</span><br><span class="line"> <span class="keyword">function</span> handleMove(e) {</span><br><span class="line"> setPostion({ x: e.clientX, y: e.clientY });</span><br><span class="line"> }</span><br><span class="line"> // 使用useEffect处理class中生命周期可以做到的事情</span><br><span class="line"> useEffect(() => {</span><br><span class="line"> // 同时可以处理 componentDidMount 以及 componentDidUpdate 中的事情</span><br><span class="line"> window.addEventListener(<span class="string">'mousemove'</span>, handleMove);</span><br><span class="line"> document.title = `(<span class="variable">${postion.x}</span>,<span class="variable">${postion.y}</span>)`;</span><br><span class="line"> <span class="built_in">return</span> () => {</span><br><span class="line"> // <span class="built_in">return</span>的<span class="keyword">function</span> 可以相当于在组件被卸载的时候执行 类似于 componentWillUnmount</span><br><span class="line"> window.removeEventListener(<span class="string">'mousemove'</span>, handleMove);</span><br><span class="line"> };</span><br><span class="line"> // [] 是参数,代表deps,也就是说react触发这个hook的时机会和传入的deps有关,内部利用object.is实现</span><br><span class="line"> // 默认不给参数会在每次render的时候调用,给空数组会导致每次比较是一样的,只执行一次,这里正确的应该是给postion</span><br><span class="line"> }, [postion]);</span><br><span class="line"> // postion 可以被直接<span class="built_in">return</span>,这样达到了逻辑的复用~,哪里需要哪里调用就可以了。</span><br><span class="line"> <span class="built_in">return</span> postion;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="built_in">export</span> default useMousePostion</span><br></pre></td></tr></table></figure>
<h3 id="通过观察,我们可以发现自定义-Hook-具有以下特点:"><a href="#通过观察,我们可以发现自定义-Hook-具有以下特点:" class="headerlink" title="通过观察,我们可以发现自定义 Hook 具有以下特点:"></a>通过观察,我们可以发现自定义 Hook 具有以下特点:</h3><ul>
<li>表面上:一个命名格式为 useXXX 的函数,但不是 React 函数式组件</li>
<li>本质上:内部通过使用 React 自带的一些 Hook (例如 useState 和 useEffect )来实现某些通用的逻辑</li>
</ul>
<h3 id="有很多地方可以去做自定义-Hook:DOM-副作用修改-监听、动画、请求、表单操作、数据存储等等。"><a href="#有很多地方可以去做自定义-Hook:DOM-副作用修改-监听、动画、请求、表单操作、数据存储等等。" class="headerlink" title="有很多地方可以去做自定义 Hook:DOM 副作用修改/监听、动画、请求、表单操作、数据存储等等。"></a>有很多地方可以去做自定义 Hook:DOM 副作用修改/监听、动画、请求、表单操作、数据存储等等。</h3><blockquote>
<p>推荐两个强大的 React Hooks 库:React Use 和 Umi Hook。它们都实现了很多生产级别的自定义 Hook。</p>
</blockquote>
<h1 id="useCallback"><a href="#useCallback" class="headerlink" title="useCallback"></a>useCallback</h1><blockquote>
<p>依赖数组在判断元素是否发生改变时使用了 Object.is 进行比较,因此当 deps 中某一元素为非原始类型时(例如函数、对象等),每次渲染都会发生改变,从而每次都会触发 Effect,失去了 deps 本身的意义。</p>
</blockquote>
<h3 id="关于-Effect-无限循环"><a href="#关于-Effect-无限循环" class="headerlink" title="关于 Effect 无限循环"></a>关于 Effect 无限循环</h3><figure class="highlight bash"><table><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><br><span class="line"><span class="keyword">function</span> useEndlessCounter({ converter = data => data }) {</span><br><span class="line"> const [counter, setCount] = useState(0);</span><br><span class="line"></span><br><span class="line"> useEffect(() => {</span><br><span class="line"> setCount(converter(counter));</span><br><span class="line"> }, [converter]);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">return</span> counter;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>我们的组件陷入了:渲染 => 触发 Effect => 修改状态 => 触发重渲染的无限循环。</p>
<h3 id="我们知道,在-JavaScript-中,原始类型和非原始类型在判断值是否相同的时候有巨大的差别:"><a href="#我们知道,在-JavaScript-中,原始类型和非原始类型在判断值是否相同的时候有巨大的差别:" class="headerlink" title="我们知道,在 JavaScript 中,原始类型和非原始类型在判断值是否相同的时候有巨大的差别:"></a>我们知道,在 JavaScript 中,原始类型和非原始类型在判断值是否相同的时候有巨大的差别:</h3><figure class="highlight bash"><table><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><br><span class="line"><span class="literal">true</span> === <span class="literal">true</span> // <span class="literal">true</span></span><br><span class="line">1 === 1 // <span class="literal">true</span></span><br><span class="line"><span class="string">'a'</span> === <span class="string">'a'</span> // <span class="literal">true</span></span><br><span class="line"></span><br><span class="line">// 非原始类型</span><br><span class="line">{} === {} // <span class="literal">false</span></span><br><span class="line">[] === [] // <span class="literal">false</span></span><br><span class="line">() => {} === () => {} // <span class="literal">false</span></span><br></pre></td></tr></table></figure>
<p>同样,每次传入的 converter 函数虽然形式上一样,但仍然是不同的函数(引用不相等),从而导致每次都会执行 Effect 函数</p>
<h3 id="关于记忆化缓存(Memoization)"><a href="#关于记忆化缓存(Memoization)" class="headerlink" title="关于记忆化缓存(Memoization)"></a>关于记忆化缓存(Memoization)</h3><p>Memoization,一般称为记忆化缓存(或者“记忆”),听上去是很高深的计算机专业术语,但是它背后的思想很简单:假如我们有一个计算量很大的纯函数(给定相同的输入,一定会得到相同的输出),那么我们在第一次遇到特定输入的时候,把它的输出结果“记”(缓存)下来,那么下次碰到同样的输出,只需要从缓存里面拿出来直接返回就可以了,省去了计算的过程!</p>
<p>实际上,除了节省不必要的计算、从而提高程序性能之外,Memoization 还有一个用途:用了保证<strong>返回值的引用相等</strong>。</p>
<p>我们先通过一段简单的求平方根的函数,熟悉一下 Memoization 的原理。首先是一个没有缓存的版本:</p>
<figure class="highlight bash"><table><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">function</span> sqrt(arg) {</span><br><span class="line"> <span class="built_in">return</span> { result: Math.sqrt(arg) }; //返回对象和后面缓存版本做对比</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>缓存版本</p>
<figure class="highlight bash"><table><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> memoizedSqrt(arg) {</span><br><span class="line"> // 如果 cache 不存在,则初始化一个空对象</span><br><span class="line"> <span class="keyword">if</span> (!memoizedSqrt.cache) {</span><br><span class="line"> memoizedSqrt.cache = {};</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 如果 cache 没有命中,则先计算,再存入 cache,然后返回结果</span><br><span class="line"> <span class="keyword">if</span> (!memoizedSqrt.cache[arg]) {</span><br><span class="line"> <span class="built_in">return</span> memoizedSqrt.cache[arg] = { result: Math.sqrt(arg) };</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 直接返回 cache 内的结果,无需计算</span><br><span class="line"> <span class="built_in">return</span> memoizedSqrt.cache[arg];</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>结果对比</p>
<figure class="highlight bash"><table><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">sqrt(9) // { result: 3 }</span><br><span class="line">sqrt(9) === sqrt(9) // <span class="literal">false</span></span><br><span class="line">Object.is(sqrt(9), sqrt(9)) // <span class="literal">false</span></span><br><span class="line"></span><br><span class="line">memoizedSqrt(9) // { result: 3 }</span><br><span class="line">memoizedSqrt(9) === memoizedSqrt(9) // <span class="literal">true</span></span><br><span class="line">Object.is(memoizedSqrt(9), memoizedSqrt(9)) // <span class="literal">true</span></span><br></pre></td></tr></table></figure>
<p>普通的 sqrt 每次返回的结果的引用都不相同(或者说是一个全新的对象),而 memoizedSqrt 则能返回完全相同的对象。因此在 React 中,通过 Memoization 可以确保多次渲染中的 Prop 或者状态的引用相等,从而能够避免不必要的重渲染或者副作用执行。</p>
<p>让我们来总结一下记忆化缓存(Memoization)的两个使用场景:</p>
<ul>
<li>通过缓存计算结果,节省费时的计算</li>
<li>保证相同输入下返回值的引用相等</li>
</ul>
<h3 id="为了解决函数在多次渲染中的引用相等(Referential-Equality)问题,React-引入了一个重要的-Hook——-useCallback"><a href="#为了解决函数在多次渲染中的引用相等(Referential-Equality)问题,React-引入了一个重要的-Hook——-useCallback" class="headerlink" title="为了解决函数在多次渲染中的引用相等(Referential Equality)问题,React 引入了一个重要的 Hook—— useCallback"></a>为了解决函数在多次渲染中的引用相等(Referential Equality)问题,React 引入了一个重要的 Hook—— useCallback</h3><p>使用方法</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">const memoizedCallback = useCallback(callback, deps);</span><br></pre></td></tr></table></figure>
<p>第一个参数 callback 就是需要记忆的函数,第二个参数就是大家熟悉的 deps 参数,同样也是一个依赖数组(有时候也被称为输入 inputs)。在 Memoization 的上下文中,这个 deps 的作用相当于缓存中的键(Key),如果键没有改变,那么就直接返回缓存中的函数,并且确保是引用相同的函数。</p>
<p>在大多数情况下,我们都是传入空数组 [] 作为 deps 参数,这样 useCallback 返回的就始终是同一个函数,永远不会更新。</p>
<blockquote>
<p>在学习 useEffect 的时候发现:我们并不需要把 useState 返回的第二个 Setter 函数作为 Effect 的依赖。实际上,React 内部已经对 Setter 函数做了 Memoization 处理,因此每次渲染拿到的 Setter 函数都是完全一样的,deps 加不加都是没有影响的。</p>
</blockquote>
<h3 id="useCallback-和-useMemo-的关系"><a href="#useCallback-和-useMemo-的关系" class="headerlink" title="useCallback 和 useMemo 的关系"></a>useCallback 和 useMemo 的关系</h3><p>useCallback 有个好基友叫 useMemo, useCallback 主要是为了解决<strong>函数</strong>的”引用相等“问题,而 useMemo 则是一个”全能型选手“,能够同时胜任引用相等和节约计算的任务</p>
<p>useMemo 的使用方法如下:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">const memoizedValue = useMemo(() => fn(a, b), [a, b]);</span><br></pre></td></tr></table></figure>
<p>其中第一个参数是一个函数,这个函数返回值的返回值 将返回给 memoizedValue 。因此以下两个钩子的使用是完全等价的:</p>
<figure class="highlight bash"><table><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">useCallback(fn, deps);</span><br><span class="line">useMemo(() => fn, deps);</span><br></pre></td></tr></table></figure>
<p>然后我们用 useCallback 去解决上面计数器无限循环的问题并且去看一个 useMemo 性能优化案例</p>
<h1 id="useReducer-和-useContext"><a href="#useReducer-和-useContext" class="headerlink" title="useReducer 和 useContext"></a>useReducer 和 useContext</h1><h3 id="useState-一个未解决的问题"><a href="#useState-一个未解决的问题" class="headerlink" title="useState 一个未解决的问题"></a>useState 一个未解决的问题</h3><p>你很有可能在使用 useState 的时候遇到过一个问题:通过 Setter 修改状态的时候,怎么读取上一个状态值,并在此基础上修改呢?如果你看文档足够细致,应该会注意到 useState 有一个函数式更新(Functional Update)的用法,以下面这段计数器(代码来自 React 官网)为例:</p>
<figure class="highlight bash"><table><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> Counter({initialCount}) {</span><br><span class="line"> const [count, setCount] = useState(initialCount);</span><br><span class="line"> <span class="built_in">return</span> (</span><br><span class="line"> <></span><br><span class="line"> Count: {count}</span><br><span class="line"> <button onClick={() => setCount(initialCount)}>Reset</button></span><br><span class="line"> <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button></span><br><span class="line"> <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button></span><br><span class="line"> </></span><br><span class="line"> );</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>可以看到,我们传入 setCount 的是一个函数,它的参数是之前的状态,返回的是新的状态,这其实就是一个 Reducer 函数</p>
<h3 id="Reducer-函数"><a href="#Reducer-函数" class="headerlink" title="Reducer 函数"></a>Reducer 函数</h3><p>我们这里将先回归最基础的概念,暂时忘掉框架相关的知识。在学习 JavaScript 基础时,你应该接触过数组的 reduce 方法,它可以用一种相当炫酷的方式实现数组求和:</p>
<figure class="highlight bash"><table><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">const nums = [1, 2, 3]</span><br><span class="line">const value = nums.reduce((acc, next) => acc + next, 0)</span><br></pre></td></tr></table></figure>
<p>其中 reduce 的第一个参数 (acc, next) => acc + next 就是一个 Reducer 函数。从表面上来看,这个函数接受一个状态的累积值 acc 和新的值 next,然后返回更新过后的累积值 acc + next</p>
<p>从更深层次来说,Reducer 函数有两个必要规则:</p>
<ul>
<li>只返回一个值</li>
<li>不修改输入值,而是返回新的值</li>
</ul>
<p>第一点很好判断,其中第二点则是很多新手踩过的坑,对比以下两个函数:</p>
<figure class="highlight bash"><table><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">// 不是 Reducer 函数! push会改变原数组</span><br><span class="line"><span class="keyword">function</span> buy(cart, thing) {</span><br><span class="line"> cart.push(thing);</span><br><span class="line"> <span class="built_in">return</span> cart;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// 正宗的 Reducer 函数</span><br><span class="line"><span class="keyword">function</span> buy(cart, thing) {</span><br><span class="line"> <span class="built_in">return</span> cart.concat(thing);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>调用数组的 push 方法,会就地修改输入的 cart 参数(是否 return 都无所谓了),违反了 Reducer 第二条规则,而下面的函数通过数组的 concat 方法返回了一个全新的数组,避免了直接修改 cart</p>
<p>此时我们在看 useState 的函数式写法 是一个很标准的 reducer 函数</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">setCount(prevCount => prevCount + 1);</span><br></pre></td></tr></table></figure>
<p>我们在之前大量地使用了 useState,你可能就此认为 useState 应该是最底层的元素了。但实际上在 React 的源码中,useState 的实现使用了 useReducer</p>
<figure class="highlight bash"><table><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">function</span> basicStateReducer(state, action) {</span><br><span class="line"> <span class="built_in">return</span> typeof action === <span class="string">'function'</span> ? action(state) : action;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="useReducer-使用浅析"><a href="#useReducer-使用浅析" class="headerlink" title="useReducer 使用浅析"></a>useReducer 使用浅析</h3><p>官方介绍的 reducer 用法</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">const [state, dispatch] = useReducer(reducer, initialArg, init);</span><br></pre></td></tr></table></figure>
<p>首先我们来看下 useReducer 需要提供哪些参数:</p>
<ol>
<li>第一个参数 reducer 显然是必须的,它的形式跟 Redux 中的 Reducer 函数完全一致,即 (state, action) => newState</li>
<li>第二个参数 initialArg 就是状态的初始值</li>
<li>第三个参数 init 是一个可选的用于懒初始化(Lazy Initialization)的函数,这个函数返回初始化后的状态</li>
</ol>
<p>返回的 state(只读状态)和 dispatch(派发函数)则比较容易理解了。我们来结合一个简单的计数器例子讲解一下</p>
<figure class="highlight bash"><table><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></pre></td><td class="code"><pre><span class="line">// Reducer 函数</span><br><span class="line"><span class="keyword">function</span> reducer(state, action) {</span><br><span class="line"> switch (action.type) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'increment'</span>:</span><br><span class="line"> <span class="built_in">return</span> { count: state.count + 1 };</span><br><span class="line"> default:</span><br><span class="line"> throw new Error();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">Counter</span></span>() {</span><br><span class="line"> const [state, dispatch] = useReducer(reducer, { count: 0 });</span><br><span class="line"> <span class="built_in">return</span> (</span><br><span class="line"> <></span><br><span class="line"> Count: {state.count}</span><br><span class="line"> <button onClick={() => dispatch({ <span class="built_in">type</span>: <span class="string">'increment'</span> })}>+</button></span><br><span class="line"> </></span><br><span class="line"> );</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>我们首先关注一下 Reducer 函数,它的两个参数 state 和 action 分别是当前状态和 dispatch 派发的动作。这里的动作就是普通的 JavaScript 对象,用来表示修改状态的操作,注意 type 是必须要有的属性,代表动作的类型。然后我们根据 action 的类型返回相应修改后的新状态。</p>
<p>然后在 Counter 组件中,我们通过 useReducer 钩子获取到了状态和 dispatch 函数,然后把这个状态渲染出来。在按钮 button 的 onClick 回调函数中,我们通过 dispatch 一个类型为 increment 的 Action 去更新状态。</p>
<h3 id="什么时候使用-useReducer"><a href="#什么时候使用-useReducer" class="headerlink" title="什么时候使用 useReducer"></a>什么时候使用 useReducer</h3><p>你也许发现,useReducer 和 useState 的使用目的几乎是一样的:定义状态和修改状态的逻辑。useReducer 使用起来较为繁琐,但如果你的状态管理出现了至少一个以下所列举的问题:</p>
<ul>
<li>需要维护的状态本身比较复杂,多个状态之间相互依赖</li>
<li>修改状态的过程比较复杂</li>
</ul>
<p><strong>就强烈建议你使用 useReducer 了</strong></p>
<p>假设我们要做一个支持撤销和重做的编辑器</p>
<figure class="highlight bash"><table><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">// 用于懒初始化的函数</span><br><span class="line"><span class="keyword">function</span> init(initialState) {</span><br><span class="line"> <span class="built_in">return</span> {</span><br><span class="line"> past: [],</span><br><span class="line"> present: initialState,</span><br><span class="line"> future: [],</span><br><span class="line"> };</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// Reducer 函数</span><br><span class="line"><span class="keyword">function</span> reducer(state, action) {</span><br><span class="line"> const { past, future, present } = state;</span><br><span class="line"> switch (action.type) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'UNDO'</span>:</span><br><span class="line"> <span class="built_in">return</span> {</span><br><span class="line"> past: past.slice(0, past.length - 1),</span><br><span class="line"> present: past[past.length - 1],</span><br><span class="line"> future: [present, ...future],</span><br><span class="line"> };</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'REDO'</span>:</span><br><span class="line"> <span class="built_in">return</span> {</span><br><span class="line"> past: [...past, present],</span><br><span class="line"> present: future[0],</span><br><span class="line"> future: future.slice(1),</span><br><span class="line"> };</span><br><span class="line"> default:</span><br><span class="line"> <span class="built_in">return</span> state;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>如果用useState来写是比较困难的</p>
<h3 id="useContext-使用浅析"><a href="#useContext-使用浅析" class="headerlink" title="useContext 使用浅析"></a>useContext 使用浅析</h3><p><img src="https://upload-images.jianshu.io/upload_images/17865205-795857b571fad178.png?imageMogr2/auto-orient/strip|imageView2/2/format/webp" alt="avatar"></p>
<p>在 Hooks 诞生之前,React 已经有了在组件树中共享数据的解决方案:Context在类组件中,我们可以通过 createContext 属性获取到最近的 Context Provider</p>
<p>从 API 名字就可以看出, createContext 能够创建一个 React 的 上下文(context),然后订阅了这个上下文的组件中,可以拿到上下文中提供的数据或者其他信息。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">const MyContext = React.createContext(defaultValue)</span><br></pre></td></tr></table></figure>
<p>使用 useContext 获取上下文</p>
<figure class="highlight bash"><table><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">// 从上面代码可以发现,useContext 需要将 MyContext 这个 Context 实例传入,不是字符串,就是实例本身。</span><br><span class="line">const {funcName} = useContext(MyContext);</span><br></pre></td></tr></table></figure>
<p>这种用法会存在一个比较尴尬的地方,父子组件不在一个目录中,如何共享 MyContext 这个 Context 实例呢?</p>
<p>一般这种情况下,会通过 Context Manager 统一管理上下文的实例,然后通过 export 将实例导出,在子组件中在将实例 import 进来。</p>
<p>案例: createContext 和 useContext 结合使用实现方法共享</p>
<blockquote>
<p>举个实际的例子:子组件中修改父组件的 state, 一般的做法是将父组件的方法比如 setXXX 通过 props 的方式传给子组件,而一旦子组件多层级的话,就要层层透传。<br>使用 Context 的方式则可以免去这种层层透传</p>
</blockquote>
<p>1、context-manager.js<br>创建一个上下文管理的组件,用来统一导出 Context 实例</p>
<figure class="highlight bash"><table><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">import React from <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">export</span> const MyContext = React.createContext(null);</span><br></pre></td></tr></table></figure>
<p>2、下面代码中,父组件引入了实例,并且通过 MyContext.Provider 将父组件包装,并且通过 Provider.value 将方法提供出去。</p>
<p> 下面的实例提供了三个 state 操作方法:</p>
<p> setStep<br> setCount<br> setNumber<br> 以及一个副作用方法:</p>
<p> fetchData<br> 使用 useReducer 减少 Context 的复杂程度</p>
<p>3、子组件 useContext 解析上下文</p>
<p>下面是子组件,相同的,也需要从 context-manager 中引入 MyContext 这个实例,然后才能通过 const { setStep, setNumber, setCount, fetchData } = useContext(MyContext); 解析出上下文中的方法,在子组件中则可以直接使用这些方法,修改父组件的 state。</p>
<p>4、使用 useReducer 减少 Context 的复杂程度</p>
<p> 上面的示例虽然实现了多级组件方法共享,但是暴露出一个问题:所有的方法都放在了 Context.Provider.value 属性中传递,必然造成整个 Context Provider 提供的方法越来越多,也会臃肿。<br> 而像 setStep、setCount、setNumber 这三个方法,是可以通过 useReducer 包装,并且通过 dispatch 触发的,因此修改一下父组件:</p>
<p>5、将 state 也通过 Context 传递给子组件</p>
<p> 上面的所有示例中,子组件获取父组件的 state 还是通过 props ,多级子组件又会存在层层嵌套<br> 如果将整个 state 通过 Context 传入就无需层层组件的 props 传递(如果不需要整个state,可以只将某几个 state 给 Provider)</p>
<blockquote>
<p>直接使用父组件 state 带来的性能问题,在点击子组件的 【number + step】 按钮的时候,虽然 count 的值没有发生任何变化,但是一直触发 re-render,即使子组件是通过 React.memo 包装过的。<br> 出现这个问题原因是 React.memo 只会对 props 进行浅比较,而通过 Context 我们直接将 state 注入到了组件内部,因此 state 的变化必然会触发 re-render,整个 state 变化是绕过了 memo。</p>
</blockquote>
<p>6、 使用 useMemo() 解决 state Context 透传的性能问题 </p>
<blockquote>
<p>既然 React.memo() 无法拦截注入到 Context 的 state 的变化,那就需要我们在组件内部进行更细粒度的性能优化,这个时候可以使用 useMemo()</p>
</blockquote>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://localhost:4000/2020/02/10/JS防抖与节流/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="Rex Wang">
<meta itemprop="description" content>
<meta itemprop="image" content="/images/avatar.gif">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="明天会更好">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2020/02/10/JS防抖与节流/" itemprop="url">JS防抖与节流</a></h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建于" itemprop="dateCreated datePublished" datetime="2020-02-10T11:03:04+08:00">
2020-02-10
</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h2 id="什么是防抖和节流?有什么区别?如何实现?"><a href="#什么是防抖和节流?有什么区别?如何实现?" class="headerlink" title="什么是防抖和节流?有什么区别?如何实现?"></a>什么是防抖和节流?有什么区别?如何实现?</h2><p><strong>防抖</strong></p>
<blockquote>
<p>触发高频率事件后n秒内函数只会执行一次,如果n秒内再次被触发,则重新计时(每次触发事件时都取消之前的延时调用方法)</p>
</blockquote>
<figure class="highlight bash"><table><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">fuction debounce(fn) {</span><br><span class="line"> <span class="built_in">let</span> timeout = null</span><br><span class="line"> <span class="built_in">return</span> <span class="function"><span class="title">function</span></span>() {</span><br><span class="line"> clearTimeout(timeout) // 清空定时器</span><br><span class="line"> timeout = setTimeOut( () => {</span><br><span class="line"> fn.apply(this, arguments);</span><br><span class="line"> } ,500)</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">say</span></span>() {</span><br><span class="line"> console.log(<span class="string">'防抖成功'</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">var input = document.getElementById(<span class="string">'inp'</span>);</span><br><span class="line">input.addEventListener(<span class="string">'input'</span>, debounce(sayHi));</span><br></pre></td></tr></table></figure>
<p><strong>节流</strong></p>
<blockquote>
<p>高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率(每次触发事件时都判断当前是否有等待执行的延时函数)</p>
</blockquote>
<figure class="highlight bash"><table><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">function</span> throttle(fn) {</span><br><span class="line"> <span class="built_in">let</span> canRun = <span class="literal">true</span>; // 通过闭包保存一个flga</span><br><span class="line"> <span class="built_in">return</span> <span class="function"><span class="title">function</span></span> () {</span><br><span class="line"> <span class="keyword">if</span> (!canRun) <span class="built_in">return</span>; // 在函数开头判断标记是否为<span class="literal">true</span>,不为<span class="literal">true</span>则<span class="built_in">return</span></span><br><span class="line"> canRun = <span class="literal">false</span>; // 立即设置为<span class="literal">false</span></span><br><span class="line"> setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中</span><br><span class="line"> fn.apply(this, arguments);</span><br><span class="line"> // 最后在setTimeout执行完毕后再把标记设置为<span class="literal">true</span>(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是<span class="literal">false</span>,在开头被<span class="built_in">return</span>掉</span><br><span class="line"> canRun = <span class="literal">true</span>;</span><br><span class="line"> }, 500);</span><br><span class="line"> };</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> sayHi(e) {</span><br><span class="line"> console.log(e.target.innerWidth, e.target.innerHeight);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">window.addEventListener(<span class="string">'resize'</span>, throttle(sayHi));</span><br></pre></td></tr></table></figure>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://localhost:4000/2020/02/06/PureComponents和Components的区别/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="Rex Wang">
<meta itemprop="description" content>
<meta itemprop="image" content="/images/avatar.gif">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="明天会更好">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2020/02/06/PureComponents和Components的区别/" itemprop="url">PureComponents和Components的区别</a></h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建于" itemprop="dateCreated datePublished" datetime="2020-02-06T15:49:15+08:00">
2020-02-06
</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<blockquote>
<p>React.Component和 React.PureComponent很相似,两则的区别在于,PureComponent类帮我们以浅比较的方式对比props和state,实现了shouldComponentUpdate()函数,在某些情况下,使用PureComponent可以减少render函数的执行,提升性能。</p>
</blockquote>
<h2 id="PureComponents能够提升性能"><a href="#PureComponents能够提升性能" class="headerlink" title="PureComponents能够提升性能"></a>PureComponents能够提升性能</h2><figure class="highlight bash"><table><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"> import React from <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"> class Index extends React.PureComponent{</span><br><span class="line"> constructor(props) {</span><br><span class="line"> super(props);</span><br><span class="line"> this.state = {</span><br><span class="line"> show: <span class="literal">false</span></span><br><span class="line"> };</span><br><span class="line"> console.log(<span class="string">'constructor'</span>);</span><br><span class="line"> }</span><br><span class="line"> changeState = () => {</span><br><span class="line"> this.setState({</span><br><span class="line"> show: <span class="literal">true</span></span><br><span class="line"> })</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="title">render</span></span>() {</span><br><span class="line"> console.log(<span class="string">'render'</span>);</span><br><span class="line"> <span class="built_in">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <button onClick={this.changeState}>Click me</button></span><br><span class="line"> <div></span><br><span class="line"> {this.state.show.toString()}</span><br><span class="line"> </div></span><br><span class="line"> </div></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="title">componentDidUpdate</span></span>() {</span><br><span class="line"> console.log(<span class="string">"componentDidUpdate"</span>)</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="built_in">export</span> default Index;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>1.初次渲染时控制台会依次打印”constructor”、”render”;<br> 2.当第一次点击按钮更新state时,控制台会依次打印”render”、 “componentDidUpdate”;<br> 3.后续每次触发点击事件,尽管show的值没有变化,控制台还是会依次打印”render”、”componentDidUpdate”,说明组件依然调用render()、componentDidUpdate()函数,显然这是多余的,通常我们会手动重新实现shouldComponentUpdate(nextProps, nextState)函数判断state、props的状态再来决定是否需要重新渲染.</p>
</blockquote>
<h2 id="PureComponent默认实现的shouldComponentUpdate-方法使用的是浅比较:-即值的比较或引用的比较-不会进行深层次的对比,所以当props或state的值是引用类型时,即使对象的值改变了,但是对象的引用没变-不会触发render(会影响子组件-最好用于纯展示函数-)"><a href="#PureComponent默认实现的shouldComponentUpdate-方法使用的是浅比较:-即值的比较或引用的比较-不会进行深层次的对比,所以当props或state的值是引用类型时,即使对象的值改变了,但是对象的引用没变-不会触发render(会影响子组件-最好用于纯展示函数-)" class="headerlink" title="PureComponent默认实现的shouldComponentUpdate()方法使用的是浅比较: 即值的比较或引用的比较, 不会进行深层次的对比,所以当props或state的值是引用类型时,即使对象的值改变了,但是对象的引用没变,不会触发render(会影响子组件,最好用于纯展示函数 )"></a>PureComponent默认实现的shouldComponentUpdate()方法使用的是浅比较: 即值的比较或引用的比较, 不会进行深层次的对比,所以当props或state的值是引用类型时,即使对象的值改变了,但是对象的引用没变,不会触发render(会影响子组件,最好用于纯展示函数 )</h2><pre><code class="bash">
import React from <span class="string">'react'</span>;
class IndexPage extends React.PureComponent{
constructor(props) {
super(props);
this.state = {
arr: [1,2,3,4,5]
};
}
changeArr = () => {
<span class="built_in">let</span> {arr} = this.state
arr.pop()
this.setState({
arr
})
console.log(<span class="string">"changeArr"</span>, arr)
};
<span class="function"><span class="title">render</span></span>() {
const { arr } = this.state
console.log(<span class="string">'render'</span>, arr);
<span class="built_in">return</span> (
<div>
<button onClick={this.changeArr}>pop</button>
<ul>
{
arr.map(item => <li key={item}>{item}</li>)
}
</ul>
</div>
);
}
<span class="function"><span class="title">componentDidUpdate</span></span>() {
console.log(<span class="string">"componentDidUpdate"</span>)
}
}
<span class="built_in">export</span> default IndexPage;
</code></pre>
<blockquote>
<p>1.当这个this.state.arr是一个数组时,且这个组件是继承自PureComponent时,初始化依旧是输出constructor和render,但是当点击按钮时,界面上没有变化,虽然数组的值发生变化,但是浅比较引用相同,不会触发页面更新。<br>2.但是当这个组件是继承自Component的时候,初始化依旧是输出constructor和render,但是当点击按钮时,界面上出现了变化,即我们打印处理的arr的值输出,而且每点击一次按钮都会输出一次render,证明已经重新渲染,this.state.arr的值已经更新,所以我们能在界面上看到这个变化<br>3.使用扩展运算符产生新数组,使this.state.arr的引用发生了变化,所以初始化的时候输出constructor和render后,每次点击按钮都会输出render,界面也会变化,不管该组件是继承自Component还是PureComponent的</p>
</blockquote>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://localhost:4000/2019/09/11/带你了解Set与Map/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="Rex Wang">
<meta itemprop="description" content>
<meta itemprop="image" content="/images/avatar.gif">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="明天会更好">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2019/09/11/带你了解Set与Map/" itemprop="url">带你了解Set与Map</a></h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建于" itemprop="dateCreated datePublished" datetime="2019-09-11T15:00:10+08:00">
2019-09-11
</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="带你了解Set与Map"><a href="#带你了解Set与Map" class="headerlink" title="带你了解Set与Map"></a>带你了解Set与Map</h1><h1 id="Set"><a href="#Set" class="headerlink" title="Set"></a>Set</h1><p>set简述:<br>Set对象是值的集合,你可以按照插入的顺序迭代它的元素。 Set中的元素只会出现一次,即 Set 中的元素是唯一的。</p>
<figure class="highlight bash"><table><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></pre></td><td class="code"><pre><span class="line">// 1.成员不能重复</span><br><span class="line">// 2.只有键值,没有键名</span><br><span class="line">// 3.可以遍历,方法有add ,delete ,has</span><br><span class="line">// 4.size返回个数</span><br><span class="line">// 5.delete 移除Set的中与这个值相等的元素</span><br><span class="line">// 6.has 返回一个布尔值,表示该值在Set中存在与否</span><br><span class="line">// 7.set.length的值为0</span><br><span class="line"></span><br><span class="line">// 实例</span><br><span class="line"><span class="built_in">let</span> mySet = new Set()</span><br><span class="line">mySet.add(1)</span><br><span class="line">mySet.add(2)</span><br><span class="line">mySet.add(3)</span><br><span class="line">mySet.add(4) // 在Set对象尾部添加一个元素。返回该Set对象。</span><br><span class="line"><span class="built_in">let</span> obj = {</span><br><span class="line"> name: <span class="string">'set'</span></span><br><span class="line">}</span><br><span class="line">mySet.add(obj)</span><br><span class="line">console.log(mySet.size) // 5</span><br><span class="line">mySet.delete(2) // 删除指定元素</span><br><span class="line">mySet.has(1) // 判断是否有某个元素 返回<span class="literal">true</span> 或者 <span class="literal">false</span></span><br><span class="line">mySet.clear() // 清空该<span class="built_in">set</span>对象</span><br><span class="line"></span><br><span class="line">// 迭代操作</span><br><span class="line"><span class="keyword">for</span> ( <span class="built_in">let</span> item of mtSet) console.log(item)</span><br><span class="line"></span><br><span class="line">// 常用于数组去重</span><br><span class="line">const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]</span><br><span class="line">console.log([...new Set(numbers)]) </span><br><span class="line">// [2, 3, 4, 5, 6, 7, 32]</span><br></pre></td></tr></table></figure>
<h1 id="Map"><a href="#Map" class="headerlink" title="Map"></a>Map</h1><p>map简述:</p>
<p>Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值</p>
<p>Object和Map的比较:<br>Objects 和 Maps 类似的是,它们都允许你按键存取一个值、删除键、检测一个键是否绑定了值。因此(并且也没有其他内建的替代方式了)过去我们一直都把对象当成 Maps 使用。不过 Maps 和 Objects 有一些重要的区别,在下列情况里使用 Map 会是更好的选择:</p>
<ol>
<li>一个Object的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值,包括函数、对象、基本类型。</li>
<li>Map 中的键值是有序的,而添加到对象中的键则不是</li>
<li>Map 可直接进行迭代,而 Object 的迭代需要先获取它的键数组,然后再进行迭代</li>
<li>Map 在涉及频繁增删键值对的场景下会有些性能优势。</li>
</ol>
<p>// 常规用法<br><figure class="highlight bash"><table><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">var myMap = new Map();</span><br><span class="line"> </span><br><span class="line">var keyObj = {},</span><br><span class="line">keyFunc = <span class="function"><span class="title">function</span></span> () {},</span><br><span class="line">keyString = <span class="string">"a string"</span>;</span><br><span class="line"> </span><br><span class="line">// 添加键</span><br><span class="line">myMap.set(keyString, <span class="string">"和键'a string'关联的值"</span>);</span><br><span class="line">myMap.set(keyObj, <span class="string">"和键keyObj关联的值"</span>);</span><br><span class="line">myMap.set(keyFunc, <span class="string">"和键keyFunc关联的值"</span>);</span><br><span class="line"></span><br><span class="line">myMap.size; // 3</span><br><span class="line"></span><br><span class="line">// 读取值</span><br><span class="line">myMap.get(keyString); // <span class="string">"和键'a string'关联的值"</span></span><br><span class="line">myMap.get(keyObj); // <span class="string">"和键keyObj关联的值"</span></span><br><span class="line">myMap.get(keyFunc); // <span class="string">"和键keyFunc关联的值"</span></span><br><span class="line"></span><br><span class="line">myMap.get(<span class="string">"a string"</span>); // <span class="string">"和键'a string'关联的值"</span></span><br><span class="line"> // 因为keyString === <span class="string">'a string'</span></span><br><span class="line">myMap.get({}); // undefined, 因为keyObj !== {}</span><br><span class="line">myMap.get(<span class="function"><span class="title">function</span></span>() {}) // undefined, 因为keyFunc !== <span class="function"><span class="title">function</span></span> () {}</span><br></pre></td></tr></table></figure></p>
<p>// map迭代</p>
<figure class="highlight bash"><table><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">var myMap = new Map();</span><br><span class="line">myMap.set(0, <span class="string">"zero"</span>);</span><br><span class="line">myMap.set(1, <span class="string">"one"</span>);</span><br><span class="line"><span class="keyword">for</span> (var [key, value] of myMap) {</span><br><span class="line">console.log(key + <span class="string">" = "</span> + value);</span><br><span class="line">}</span><br><span class="line">// 将会显示两个<span class="built_in">log</span>。一个是<span class="string">"0 = zero"</span>另一个是<span class="string">"1 = one"</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (var key of myMap.keys()) {</span><br><span class="line">console.log(key);</span><br><span class="line">}</span><br><span class="line">// 将会显示两个<span class="built_in">log</span>。 一个是 <span class="string">"0"</span> 另一个是 <span class="string">"1"</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (var value of myMap.values()) {</span><br><span class="line">console.log(value);</span><br><span class="line">}</span><br><span class="line">// 将会显示两个<span class="built_in">log</span>。 一个是 <span class="string">"zero"</span> 另一个是 <span class="string">"one"</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (var [key, value] of myMap.entries()) {</span><br><span class="line">console.log(key + <span class="string">" = "</span> + value);</span><br><span class="line">}</span><br><span class="line">// 将会显示两个<span class="built_in">log</span>。 一个是 <span class="string">"0 = zero"</span> 另一个是 <span class="string">"1 = one"</span></span><br></pre></td></tr></table></figure>
<p>// map与数组的关系</p>
<figure class="highlight bash"><table><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">var kvArray = [[<span class="string">"key1"</span>, <span class="string">"value1"</span>], [<span class="string">"key2"</span>, <span class="string">"value2"</span>]];</span><br><span class="line"></span><br><span class="line">// 使用常规的Map构造函数可以将一个二维键值对数组转换成一个Map对象</span><br><span class="line">var myMap = new Map(kvArray);</span><br><span class="line"></span><br><span class="line">myMap.get(<span class="string">"key1"</span>); // 返回值为 <span class="string">"value1"</span></span><br><span class="line"></span><br><span class="line">// 使用Array.from函数可以将一个Map对象转换成一个二维键值对数组</span><br><span class="line">console.log(Array.from(myMap)); // 输出和kvArray相同的数组</span><br><span class="line"></span><br><span class="line">// 或者在键或者值的迭代器上使用Array.from,进而得到只含有键或者值的数组</span><br><span class="line">console.log(Array.from(myMap.keys())); // 输出 [<span class="string">"key1"</span>, <span class="string">"key2"</span>]</span><br></pre></td></tr></table></figure>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="http://localhost:4000/2019/07/21/小程序问题总结,也许你也遇到过/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="Rex Wang">
<meta itemprop="description" content>
<meta itemprop="image" content="/images/avatar.gif">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="明天会更好">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2019/07/21/小程序问题总结,也许你也遇到过/" itemprop="url">小程序问题总结,也许你也遇到过</a></h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建于" itemprop="dateCreated datePublished" datetime="2019-07-21T17:21:51+08:00">
2019-07-21
</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="小程序常见问题汇总"><a href="#小程序常见问题汇总" class="headerlink" title="小程序常见问题汇总"></a>小程序常见问题汇总</h1><h2 id="wx-showToast-在真机调试时一闪而过"><a href="#wx-showToast-在真机调试时一闪而过" class="headerlink" title="wx.showToast 在真机调试时一闪而过"></a>wx.showToast 在真机调试时一闪而过</h2><p>原因: wx.showLoading和wx.showToast调用的是同一个框,<br>都受 wx.hideToast() 或者 wx.hideLoading() 的影响。<br>比如在真机上你的代码顺序为 wx.showLoading() =>wx.hideLoading() => wx.showToast() ;<br>但是实际你看到的现象是 wx.showLoading() => wx.showToast() =>wx.hideLoading(),<br>受到最后的 wx.hideLoading() 影响,toast 框闪烁一下就消失<br>解决办法:<br>将showTotast放到执行队列的最后</p>
<figure class="highlight bash"><table><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">setTimeout(() => {</span><br><span class="line"> wx.showToast({</span><br><span class="line"> title: <span class="string">'我也是有底线的'</span>,</span><br><span class="line"> icon: <span class="string">"success"</span>,</span><br><span class="line"> });</span><br><span class="line"> setTimeout(() => {</span><br><span class="line"> wx.hideToast();</span><br><span class="line"> }, 2000)</span><br><span class="line">}, 0);</span><br></pre></td></tr></table></figure>
<h2 id="如何设置输入框中placeholder中的样式"><a href="#如何设置输入框中placeholder中的样式" class="headerlink" title="如何设置输入框中placeholder中的样式"></a>如何设置输入框中placeholder中的样式</h2><p>小程序内部提供了 placeholder-style这个属性,通过这个属性我们可以很方便的操作其样式</p>
<h2 id="小程序路由跳转的几种方式"><a href="#小程序路由跳转的几种方式" class="headerlink" title="小程序路由跳转的几种方式"></a>小程序路由跳转的几种方式</h2><p>1.<br>// 会有左上角的返回按钮<br>wx.navigateTo(Object object)<br>保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层。<br>2.<br>// 不会出现左上角返回按钮,适用于登录完,不可返回登录页面<br>wx.redirectTo(Object object)<br>关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。<br>3.<br>wx.reLaunch(Object object)<br>关闭所有页面,打开到应用内的某个页面<br>4.<br>wx.switchTab(Object object)<br>跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面</p>
<h2 id="小程序引入外部字体文件"><a href="#小程序引入外部字体文件" class="headerlink" title="小程序引入外部字体文件"></a>小程序引入外部字体文件</h2><p>1.首先到字体包ttf、eot、svg、woff随便一种格式文件<br>2.字体文件转换网站 链接: <a href="https://transfonter.org/" target="_blank" rel="noopener">查看</a>,限制最大10M的字体包,不建议太大字体,小程序需要做分包处理。<br><img src="/2019/07/21/小程序问题总结,也许你也遇到过/CNAME.png" title="img"><br>3.跟components同级,新建一个style文件夹,里面放第二步转换完下载后的得到的那些后缀文件(eot,svg,ttf,woff,woff2)<br>4.在style文件夹里,新建.wxss的css文件,打开下载的文件,找到stylesheet.css,将里面的全部内容复制到新建的.wxss中<br>找到需要引用字体库的wxss文件,用import 方式引入字体库css@import ‘../../style/knckout.wxss’; </p>
<figure class="highlight bash"><table><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">@font-face {</span><br><span class="line"> font-family: <span class="string">'DIN Next LT Pro'</span>;</span><br><span class="line"> src: url(base64字体编码)</span><br><span class="line"> font-weight: normal;</span><br><span class="line"> font-style: normal;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="小程序父子组件传值"><a href="#小程序父子组件传值" class="headerlink" title="小程序父子组件传值"></a>小程序父子组件传值</h2><p>1.父传子</p>
<figure class="highlight bash"><table><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></pre></td><td class="code"><pre><span class="line">// 定义组件 需要在组件.json文件中加入 <span class="string">"component"</span>: <span class="literal">true</span>, 声明其是一个组件</span><br><span class="line">// 子组件</span><br><span class="line">Component({</span><br><span class="line"> behaviors: [],</span><br><span class="line"> properties: { // 父组件传给子组件的值,类似vue的props属性</span><br><span class="line"> list:{</span><br><span class="line"> <span class="built_in">type</span>:String,</span><br><span class="line"> value: []</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> data: { }, // 私有数据,可用于模版渲染</span><br><span class="line"> // 生命周期函数,可以为函数,或一个在methods段中定义的方法名</span><br><span class="line"> attached: <span class="function"><span class="title">function</span></span> () { },</span><br><span class="line"> moved: <span class="function"><span class="title">function</span></span> () { },</span><br><span class="line"> detached: <span class="function"><span class="title">function</span></span> () { },</span><br><span class="line"> methods: { }</span><br><span class="line">})</span><br><span class="line">// 父组件</span><br><span class="line"><my-components list=<span class="string">"{{parentList}}"</span> ></my-components></span><br></pre></td></tr></table></figure>
<p>2.子传父</p>
<figure class="highlight bash"><table><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><br><span class="line">// 通过<span class="built_in">bind</span>给子组件绑定事件</span><br><span class="line"><my-components <span class="built_in">bind</span>:toChildren=<span class="string">'parentMethods'</span> list=<span class="string">"{{parentList}}"</span> ></my-components></span><br><span class="line">// 子组件</span><br><span class="line">Component({</span><br><span class="line"> behaviors: [],</span><br><span class="line"> properties: { // 父组件传给子组件的值,类似vue的props属性</span><br><span class="line"> list:{</span><br><span class="line"> <span class="built_in">type</span>:String,</span><br><span class="line"> value: []</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> data: {</span><br><span class="line"> num: 0</span><br><span class="line"> }, // 私有数据,可用于模版渲染</span><br><span class="line"> // 生命周期函数,可以为函数,或一个在methods段中定义的方法名</span><br><span class="line"> attached: <span class="function"><span class="title">function</span></span> () { },</span><br><span class="line"> moved: <span class="function"><span class="title">function</span></span> () { },</span><br><span class="line"> detached: <span class="function"><span class="title">function</span></span> () { },</span><br><span class="line"> methods: {</span><br><span class="line"> sendNumToParent: <span class="keyword">function</span>(e){</span><br><span class="line"> // 通过this.triggerEvent 可以获取父组件的方法</span><br><span class="line"> this.triggerEvent(<span class="string">'event'</span>,this.data.num) 可以调用父组件的方法,并可传入参数</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">})</span><br></pre></td></tr></table></figure>
</div>
<footer class="post-footer">