-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
250 lines (151 loc) · 120 KB
/
atom.xml
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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>乐观的阿珍</title>
<subtitle>song_yz@buaa.edu.cn</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://yoursite.com/"/>
<updated>2021-06-01T07:14:59.791Z</updated>
<id>http://yoursite.com/</id>
<author>
<name>Hain Song</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>Jenkins凭证配置</title>
<link href="http://yoursite.com/2021/06/01/Jenkins%E5%87%AD%E8%AF%81%E9%85%8D%E7%BD%AE/"/>
<id>http://yoursite.com/2021/06/01/Jenkins凭证配置/</id>
<published>2021-06-01T07:02:32.000Z</published>
<updated>2021-06-01T07:14:59.791Z</updated>
<content type="html"><![CDATA[<p>来源:git仓库切换后,jenkins上编译的配置也需要修改对应的仓库地址,此时需要配置一个新的仓库地址的凭证才能正常进行编译。<br><a id="more"></a></p><h2 id="git仓库ssh配置"><a href="#git仓库ssh配置" class="headerlink" title="git仓库ssh配置"></a>git仓库ssh配置</h2><h3 id="1-生成ssh-key"><a href="#1-生成ssh-key" class="headerlink" title="1. 生成ssh key"></a>1. 生成ssh key</h3><p>以windows为例,直接在命令行里执行,所有选项都是默认,一直回车即可生成。生成之后在.ssh文件夹下就会生成一对ssh文件。具体路径(C:\Users\${你的用户名}.ssh)<br>其中id_rsa是私钥文件,id_rsa.pub是公钥文件。<br>如果之前本地已有ssh文件则可以跳过此步骤。<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh-keygen -t rsa -C <span class="string">"your_email@youremail.com"</span></span><br></pre></td></tr></table></figure></p><p><img src="/2021/06/01/Jenkins凭证配置/1.png" alt="1"></p><h3 id="2-在git仓库中配置ssh公钥"><a href="#2-在git仓库中配置ssh公钥" class="headerlink" title="2. 在git仓库中配置ssh公钥"></a>2. 在git仓库中配置ssh公钥</h3><p>以公司用的云效代码仓库为例(其他仓库如github等操作同理),<br>首先点击右上角的头像,在菜单中点击“个人设置”<br><img src="/2021/06/01/Jenkins凭证配置/2.png" alt="2"><br>在弹出窗口中选择“SSH公钥”,在公钥处将本地的id_rsa.pub文件的内容粘贴过来,标题自己取一个就可以<br><img src="/2021/06/01/Jenkins凭证配置/3.png" alt="3"><br>添加成功后下方会显示你已经配置过的公钥,此时git仓库相关配置已完毕<br><img src="/2021/06/01/Jenkins凭证配置/4.png" alt="4"></p><h2 id="jenkins仓库ssh配置"><a href="#jenkins仓库ssh配置" class="headerlink" title="jenkins仓库ssh配置"></a>jenkins仓库ssh配置</h2><h3 id="1-打开添加凭据页面"><a href="#1-打开添加凭据页面" class="headerlink" title="1. 打开添加凭据页面"></a>1. 打开添加凭据页面</h3><p>在jenkins首页选择“凭据 -> 系统 -> 全局凭据 -> 添加凭据”<br><img src="/2021/06/01/Jenkins凭证配置/5.png" alt="5"></p><h3 id="2-添加凭据"><a href="#2-添加凭据" class="headerlink" title="2. 添加凭据"></a>2. 添加凭据</h3><p>在“类型“选项中选择”SSH Username with private key“,并勾选下方”Private Key”选项中的“Enter directly”,再点击右侧的“Add”按钮,将本地的id_rsa文件的内容粘贴到”Private Key”选项中,给Username起一个名称,最后点击“确定”即可为jenkins添加一个凭据<br><img src="/2021/06/01/Jenkins凭证配置/6.png" alt="6"></p><h2 id="选择新的凭证"><a href="#选择新的凭证" class="headerlink" title="选择新的凭证"></a>选择新的凭证</h2><h3 id="1-选择凭证"><a href="#1-选择凭证" class="headerlink" title="1. 选择凭证"></a>1. 选择凭证</h3><ol><li>在jenkins中选择一个项目,点击“配置”,在配置中找到源码管理,此处的“Repository URL”对应了该项目要使用的源码地址,在此处输入新的源码地址(如下图所示即可找到地址),并在下方“Credentials”中选择新建的和该仓库对应的凭证即可完成配置(点击右侧”添加按钮也可以走上面的添加凭证的流程”)。<br><img src="/2021/06/01/Jenkins凭证配置/7.png" alt="7"><br><img src="/2021/06/01/Jenkins凭证配置/8.png" alt="8"></li></ol><h3 id="2-此时项目应该就可以顺利编译了,撒花★-°-☆- ̄▽ ̄-°★-。"><a href="#2-此时项目应该就可以顺利编译了,撒花★-°-☆- ̄▽ ̄-°★-。" class="headerlink" title="2. 此时项目应该就可以顺利编译了,撒花★,°:.☆( ̄▽ ̄)/$:.°★ 。"></a>2. 此时项目应该就可以顺利编译了,撒花<em>★,°</em>:.☆( ̄▽ ̄)/$:<em>.°★</em> 。</h3>]]></content>
<summary type="html">
<p>来源:git仓库切换后,jenkins上编译的配置也需要修改对应的仓库地址,此时需要配置一个新的仓库地址的凭证才能正常进行编译。<br></p>
</summary>
<category term="项目配置" scheme="http://yoursite.com/categories/%E9%A1%B9%E7%9B%AE%E9%85%8D%E7%BD%AE/"/>
<category term="前端基础" scheme="http://yoursite.com/tags/%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title>React Native视频缓存解决方案</title>
<link href="http://yoursite.com/2020/07/31/React%20Native%E8%A7%86%E9%A2%91%E7%BC%93%E5%AD%98%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/"/>
<id>http://yoursite.com/2020/07/31/React Native视频缓存解决方案/</id>
<published>2020-07-31T08:49:08.000Z</published>
<updated>2020-07-31T08:51:52.044Z</updated>
<content type="html"><![CDATA[<p>憨憨最近接了个需求,要实现视频缓存功能,经历了三天的踩坑,于是有了这篇文章。</p><p>由于是React-Native的项目,对于文件相关的操作采用了react-native-fs。如果是其他项目,整体思路基本没有变动,可能会需要使用js来操作文件。</p><p>参考文章:<br><a href="https://www.jianshu.com/p/e97f6555a070" target="_blank" rel="noopener">https://www.jianshu.com/p/e97f6555a070</a> m3u8格式详解<br><a href="https://github.com/itinance/react-native-fs" target="_blank" rel="noopener">https://github.com/itinance/react-native-fs</a> react-native-fs用法<br><a href="https://github.com/vikeri/react-native-background-job" target="_blank" rel="noopener">https://github.com/vikeri/react-native-background-job</a> react-native-background-job用法<br><a id="more"></a></p><h2 id="First-of-All,理解m3u8的缓存过程"><a href="#First-of-All,理解m3u8的缓存过程" class="headerlink" title="First of All,理解m3u8的缓存过程"></a>First of All,理解m3u8的缓存过程</h2><ol><li>下载m3u8文件到本地,并记录m3u8所在的服务器地址(后续下载ts文件会用到)</li><li>读取m3u8文件,遍历每一行找出ts文件列表(tsList)和密钥key的下载地址(keyUrl)</li><li>遍历下载ts文件,如有失败,则重试</li><li>下载密钥文件,再次读取m3u8文件,并将其中的keyUrl替换成本地密钥文件的路径(相对路径即可)</li><li>此时播放m3u8文件,会直接从本地获取密钥去解密视频进行播放。<br><strong>PS:m3u8、ts文件、密钥文件建议在同一个目路下</strong></li></ol><p>最终生成m3u8文件格式如下:<br><code>#EXTM3U</code><br><code>#EXT-X-VERSION:3</code><br><code>#EXT-X-ALLOW-CACHE:YES</code><br><code>#EXT-X-TARGETDURATION:18</code><br><code>#EXT-X-MEDIA-SEQUENCE:0</code><br><code>#EXT-X-KEY:METHOD=AES-128,URI="hd.key"</code><br><code>#EXTINF:17.360000,</code><br><code>hd-00001.ts</code><br><code>#EXTINF:10.000000,</code><br><code>hd-00002.ts</code></p><p>目录如下:hd.m3u8,hd00001.ts,hd00002.ts,…,hd.key</p><p>具体流程如下:<br><img src="/2020/07/31/React Native视频缓存解决方案/视频缓存流程图.png" alt="视频缓存流程图"></p><h2 id="总体设计"><a href="#总体设计" class="headerlink" title="总体设计"></a>总体设计</h2><p>前提:当前需求仅支持一个正在进行的下载任务。<br>一开始计划是分成三个模块:视频缓存类 + 视频缓存管理 + 视频缓存列表的本地缓存管理;随着开发的进行,发现三个模块并不能满足开发需求(可能是菜),于是最终采用了四个模块的方案。<br>总体设计图如下:<br><img src="/2020/07/31/React Native视频缓存解决方案/视频缓存总体设计.png" alt="视频缓存总体设计"></p><h2 id="详细设计"><a href="#详细设计" class="headerlink" title="详细设计"></a>详细设计</h2><p><strong>DownloadVideoClass</strong><br><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// PROPS </span></span><br><span class="line"> public id: number; <span class="comment">// id </span></span><br><span class="line"> public title: string; <span class="comment">// title</span></span><br><span class="line"> public type: VIDEO_TYPE; <span class="comment">// 视频type -ld -sd -hd</span></span><br><span class="line"> public url: string; <span class="comment">// m3u8的url</span></span><br><span class="line"> public size: number; <span class="comment">// 预计总文件大小</span></span><br><span class="line"> public serverDir: string; <span class="comment">// 服务器路径 -m3u8和ts文件所在目录</span></span><br><span class="line"> public folderName: string; <span class="comment">// 本地创建文件夹名 -与m3u8同名 -eg: c1c102cbf2ae973811c782720d49120e</span></span><br><span class="line"> public tsList: TSItem[]; <span class="comment">// ts文件列表</span></span><br><span class="line"> public keyUrl: string; <span class="comment">// 密钥地址</span></span><br><span class="line"> public progress: number; <span class="comment">// 总下载进度</span></span><br><span class="line"> public indexHasDone: boolean; <span class="comment">// m3u8索引是否下载完成</span></span><br><span class="line"> public keyHasDone: boolean; <span class="comment">// 密钥是否下载完成</span></span><br><span class="line"> public m3u8Path: string; <span class="comment">// 本地m3u8路径</span></span><br><span class="line"> public parentId: number; <span class="comment">// 父级id</span></span><br><span class="line"> public parentTitle: string; <span class="comment">// 父级title</span></span><br><span class="line"> public isPaused: boolean; <span class="comment">// 是否暂停</span></span><br><span class="line"> public isFailed: boolean; <span class="comment">// 是否失败</span></span><br><span class="line"> public failedCount: number; <span class="comment">// 失败计数器</span></span><br><span class="line"> public startTime: string; <span class="comment">// 下载开始时间</span></span><br><span class="line"> public continueTime: <span class="built_in">Date</span>; <span class="comment">// 下载继续时间 用于计算下载时间</span></span><br><span class="line"> public duration: number; <span class="comment">// 下载时间</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 回调函数</span></span><br><span class="line"> public onSuccess: <span class="function">(<span class="params">data: DownloadVideoObject</span>) =></span> <span class="keyword">void</span>; <span class="comment">// 下载成功回调</span></span><br><span class="line"> public onProgress: <span class="function">(<span class="params">data: DownloadVideoObject</span>) =></span> <span class="keyword">void</span>; <span class="comment">// 进度回调 -m3u8 ts key下载成功时调用</span></span><br><span class="line"> public onDelete: <span class="function">(<span class="params">data: DownloadVideoObject</span>) =></span> <span class="keyword">void</span>; <span class="comment">// 删除下载任务回调</span></span><br><span class="line"> public onStart: <span class="function">(<span class="params">data: DownloadVideoObject</span>) =></span> <span class="keyword">void</span>; <span class="comment">// 开始下载任务回调</span></span><br><span class="line"> public onPause: <span class="function">(<span class="params">data: DownloadVideoObject</span>) =></span> <span class="keyword">void</span>; <span class="comment">// 暂停下载任务回调</span></span><br><span class="line"> public onFail: <span class="function">(<span class="params">data: DownloadVideoObject</span>) =></span> <span class="keyword">void</span>; <span class="comment">// 下载失败回调</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 下载过程中需要维护的参数</span></span><br><span class="line"> public downloadQueue: string[]; <span class="comment">// 下载ts队列</span></span><br><span class="line"> public tsSuccessSubscription: any; <span class="comment">// ts下载成功监听器</span></span><br></pre></td></tr></table></figure></p><p>具体下载流程上文已经提过,再列几个比较重要的功能点</p><ol><li>下载失败判定:采用了计数器的方式,每有一个任务下载失败便会+1,只要有一个任务成功便会清零。当计数器达到设定的阈值时判定为当前下载任务失败。(对于m3u8文件,阈值设定为10。后续的阈值设为ts文件数量的2倍)</li><li>ts下载队列管理:最初的写法是将所有的ts分片同时下载,在下载大文件时(200M以上)会有大量下载任务并行开启,导致手机巨卡并且有大量任务下载失败,很容易触发下载失败的条件。于是设置了一个ts下载队列,最多允许x个ts任务下载,监听器会监听ts分片下载成功的事件,将成功的ts从队列里弹出,取最近的未完成的ts放进队列开始下载。直到所有ts下载完成</li><li>下载key的token问题(踩坑):下载密钥时需要在密钥地址后面拼上参数MtsHlsUriToken,需要调用/video/get接口拿带有MtsHlsUriToken的m3u8文件,从其中取出MtsHlsUriToken拼到密钥下载地址的后面,才能成功下载密钥。(如没有token,会报下载成功,但是木有实际的key文件)</li></ol><p><strong>DownloadVideoManage</strong><br>维护全局唯一的下载实例,提供初始化(单个/多个)下载实例,以及获取/删除/暂停当前下载实例等操作,以及其他RNFS的操作:删除本地文件</p><p><strong>DownloadVideoOperation</strong><br>提供下载实例调用的钩子函数以及外部可调用的函数:开始/暂停、全部开始/暂定、删除等</p><p><strong>DownloadVideoStore</strong><br>缓存全局所有的下载任务,以及对缓存的相关操作</p><p>小逻辑:有个需求是这样的:排列时:正在下载的任务是先添加的在上,已完成的任务时先完成的在上。<br>由于全部任务缓存在一个数组中,在添加下载任务时从队列后插入,正序读取正在下载的任务;而当任务完成后,将任务弹出,重新放入数组最后,正序读取下载完成的任务即可。</p><p><strong>与页面的通信</strong><br>页面会添加各种事件的监听器(下载成功、失败、暂停等等),每当监听到事件发生时,便会更新数据和视图</p><p><strong>后台下载</strong><br>使用react-native-background-job,该库依赖于React Native的HeadlessJS ,目前只支持Android。</p><p><strong>当前存在的问题</strong></p><ol><li>iOS后台下载暂未实现</li><li>下载key相关部分代码过于耦合</li><li>不支持多个任务同时下载</li></ol>]]></content>
<summary type="html">
<p>憨憨最近接了个需求,要实现视频缓存功能,经历了三天的踩坑,于是有了这篇文章。</p>
<p>由于是React-Native的项目,对于文件相关的操作采用了react-native-fs。如果是其他项目,整体思路基本没有变动,可能会需要使用js来操作文件。</p>
<p>参考文章:<br><a href="https://www.jianshu.com/p/e97f6555a070" target="_blank" rel="noopener">https://www.jianshu.com/p/e97f6555a070</a> m3u8格式详解<br><a href="https://github.com/itinance/react-native-fs" target="_blank" rel="noopener">https://github.com/itinance/react-native-fs</a> react-native-fs用法<br><a href="https://github.com/vikeri/react-native-background-job" target="_blank" rel="noopener">https://github.com/vikeri/react-native-background-job</a> react-native-background-job用法<br></p>
</summary>
<category term="React Native" scheme="http://yoursite.com/categories/React-Native/"/>
<category term="解决方案" scheme="http://yoursite.com/tags/%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/"/>
</entry>
<entry>
<title>小程序navigateTo传参被截断</title>
<link href="http://yoursite.com/2020/06/30/%E5%B0%8F%E7%A8%8B%E5%BA%8FnavigateTo%E4%BC%A0%E5%8F%82%E8%A2%AB%E6%88%AA%E6%96%AD/"/>
<id>http://yoursite.com/2020/06/30/小程序navigateTo传参被截断/</id>
<published>2020-06-30T02:51:39.000Z</published>
<updated>2020-06-30T03:05:38.399Z</updated>
<content type="html"><![CDATA[<p>背景:最近在开发公司的小程序项目,为了方便采用了直接嵌入webview的方式开发,其中支付流程需要从webview跳转到小程序内完成。<br>h5调用下单接口后会通过wx.miniProgram.navigateTo跳转到小程序页面进行支付操作。<br>此时会以query的方式携带大量的参数,而直接将这些参数传递的话,会在小程序的onLoad里发现query被截断了。</p><a id="more"></a><p>解决方法:需要将参数进行编码后再传递。<br>似乎其他通过query传参的场景也适用。</p><figure class="highlight javascript"><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">h5:</span><br><span class="line">wx.navigateTo({</span><br><span class="line"> url: <span class="string">'/pages/pay/index?payData='</span> + <span class="built_in">encodeURIComponent</span>(payData)</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">小程序:</span><br><span class="line">onLoad: <span class="function"><span class="keyword">function</span> (<span class="params">query</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> url = <span class="built_in">decodeURIComponent</span>(query.payData);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>背景:最近在开发公司的小程序项目,为了方便采用了直接嵌入webview的方式开发,其中支付流程需要从webview跳转到小程序内完成。<br>h5调用下单接口后会通过wx.miniProgram.navigateTo跳转到小程序页面进行支付操作。<br>此时会以query的方式携带大量的参数,而直接将这些参数传递的话,会在小程序的onLoad里发现query被截断了。</p>
</summary>
<category term="小程序" scheme="http://yoursite.com/categories/%E5%B0%8F%E7%A8%8B%E5%BA%8F/"/>
<category term="前端踩坑" scheme="http://yoursite.com/tags/%E5%89%8D%E7%AB%AF%E8%B8%A9%E5%9D%91/"/>
</entry>
<entry>
<title>自定义React Hooks</title>
<link href="http://yoursite.com/2020/06/24/%E8%87%AA%E5%AE%9A%E4%B9%89React%20Hooks/"/>
<id>http://yoursite.com/2020/06/24/自定义React Hooks/</id>
<published>2020-06-24T08:49:28.000Z</published>
<updated>2020-06-24T09:33:06.851Z</updated>
<content type="html"><![CDATA[<p>接上一篇笔记,了解常用自定义Hooks的写法,能够手写简单Hook。</p><p>后续有常用的hook会整理在这里。</p><p>参考文章:<a href="https://blog.csdn.net/KlausLily/article/details/104586371" target="_blank" rel="noopener">https://blog.csdn.net/KlausLily/article/details/104586371</a></p><a id="more"></a><h2 id="1-自定义useState-?"><a href="#1-自定义useState-?" class="headerlink" title="1.自定义useState ?"></a>1.自定义useState ?</h2><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { useEffect, useRef, useState } <span class="keyword">from</span> <span class="string">'react'</span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">const</span> useXState = <span class="function">(<span class="params">initState</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> [state, setState] = useState(initState)</span><br><span class="line"> <span class="keyword">let</span> isUpdate = useRef()</span><br><span class="line"><span class="comment">// cb 回调赋值函数? - callback</span></span><br><span class="line"> <span class="keyword">const</span> setXState = <span class="function">(<span class="params">state, cb</span>) =></span> {</span><br><span class="line"> setState(<span class="function"><span class="params">prev</span> =></span> {</span><br><span class="line"> isUpdate.current = cb</span><br><span class="line"><span class="comment">// setState可能传值setCount(count+1)或者函数setCount(prevCount => prevCount+1),返回新值</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">typeof</span> state === <span class="string">'function'</span> ? state(prev) : state</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="keyword">if</span>(isUpdate.current) {</span><br><span class="line"><span class="comment">// 手动调用回调赋值函数</span></span><br><span class="line"> isUpdate.current()</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> [state, setXState]</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> useXState</span><br></pre></td></tr></table></figure><p>利用useRef的特性来作为标识区分是挂载还是更新,当执行setXstate时,会传入和setState一模一样的参数,并且将回调赋值给useRef的current属性,这样在更新完成时,我们手动调用current即可实现更新后的回调这一功能。<br>迷惑:cb是哪来的???在日志中打印cb是个undefined????</p><h2 id="2-useThrottle-amp-useDebounce"><a href="#2-useThrottle-amp-useDebounce" class="headerlink" title="2.useThrottle & useDebounce"></a>2.useThrottle & useDebounce</h2><figure class="highlight javascript"><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><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 节流</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">throttle</span>(<span class="params">func, ms</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> previous = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> now = <span class="built_in">Date</span>.now();</span><br><span class="line"> <span class="keyword">let</span> context = <span class="keyword">this</span>;</span><br><span class="line"> <span class="keyword">let</span> args = <span class="built_in">arguments</span>;</span><br><span class="line"> <span class="keyword">if</span> (now - previous > ms) {</span><br><span class="line"> func.apply(context, args);</span><br><span class="line"> previous = now;</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="comment">// useThrottle 回调函数 时间间隔 依赖项数组</span></span><br><span class="line"><span class="keyword">const</span> useThrottle = <span class="function">(<span class="params">fn, ms = <span class="number">30</span>, deps = []</span>) =></span> {</span><br><span class="line"> <span class="keyword">let</span> previous = useRef(<span class="number">0</span>)</span><br><span class="line"> <span class="keyword">let</span> [time, setTime] = useState(ms)</span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="keyword">let</span> now = <span class="built_in">Date</span>.now();</span><br><span class="line"> <span class="keyword">if</span> (now - previous.current > time) {</span><br><span class="line"> fn();</span><br><span class="line"> previous.current = now;</span><br><span class="line"> }</span><br><span class="line"> }, deps)</span><br><span class="line"><span class="comment">// 取消节流,可以忽略</span></span><br><span class="line"> <span class="keyword">const</span> cancel = <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> setTime(<span class="number">0</span>)</span><br><span class="line"> }v</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> [cancel]</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 节流setB,cancel为取消函数</span></span><br><span class="line"><span class="keyword">const</span> [cancel] = useThrottle(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> setB(a)</span><br><span class="line"> }, <span class="number">2000</span>, [a])</span><br></pre></td></tr></table></figure><figure class="highlight javascript"><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><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 防抖</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">debounce</span>(<span class="params">func, ms</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> timeout;</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> context = <span class="keyword">this</span>;</span><br><span class="line"> <span class="keyword">let</span> args = <span class="built_in">arguments</span>;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> (timeout) clearTimeout(timeout);</span><br><span class="line"> </span><br><span class="line"> timeout = setTimeout(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> func.apply(context, args)</span><br><span class="line"> }, ms);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// useDebounce</span></span><br><span class="line"><span class="keyword">const</span> useDebounce = <span class="function">(<span class="params">fn, ms = <span class="number">30</span>, deps = []</span>) =></span> {</span><br><span class="line"> <span class="keyword">let</span> timeout = useRef()</span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="keyword">if</span> (timeout.current) clearTimeout(timeout.current)</span><br><span class="line"> timeout.current = setTimeout(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> fn()</span><br><span class="line"> }, ms)</span><br><span class="line"> }, deps)</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">const</span> cancel = <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> clearTimeout(timeout.current)</span><br><span class="line"> timeout = <span class="literal">null</span></span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> [cancel]</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 防抖setB,cancel为取消函数</span></span><br><span class="line"><span class="keyword">const</span> [cancel] = useDebounce(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> setB(a)</span><br><span class="line"> }, <span class="number">2000</span>, [a])</span><br></pre></td></tr></table></figure><h2 id="n-useInitRender"><a href="#n-useInitRender" class="headerlink" title="n.useInitRender"></a>n.useInitRender</h2><p>在当前参与开发的React-Native项目中,会有部分页面在刚进入时直接请求数据,会导致渲染和请求同步进行 => 部分机型上会卡顿,为了简化操作,自定义了一个简易的UseInitRender Hook。用来代替RN中进入页面即请求数据的useEffect。</p><figure class="highlight javascript"><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><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line">interface InitRenderProp {</span><br><span class="line"> request?: <span class="function"><span class="params">()</span> =></span> <span class="keyword">void</span>; <span class="comment">// 请求函数</span></span><br><span class="line"> action?: <span class="function"><span class="params">()</span> =></span> <span class="keyword">void</span>; <span class="comment">// 普通函数逻辑</span></span><br><span class="line"> willFocus?: <span class="function"><span class="params">()</span> =></span> <span class="keyword">void</span>; <span class="comment">// 监听函数(返回该页面时会调用,例如重新刷新数据) </span></span><br><span class="line"> didFocus?: <span class="function"><span class="params">()</span> =></span> <span class="keyword">void</span>; <span class="comment">// 监听函数(返回该页面时会调用,例如重新刷新数据) </span></span><br><span class="line"> navigation?: NavigationScreenProp< <span class="comment">// 用于添加监听</span></span><br><span class="line"> NavigationRoute<NavigationParams>,</span><br><span class="line"> NavigationParams</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">const</span> useInitRender = (props: InitRenderProp): <span class="function"><span class="params">void</span> =></span> {</span><br><span class="line"> <span class="keyword">const</span> { request, action, willFocus, didFocus, navigation } = props;</span><br><span class="line"></span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span>: <span class="params">void</span> | (<span class="params">(</span>) =></span> <span class="keyword">void</span>) => {</span><br><span class="line"> <span class="keyword">if</span> (request) {</span><br><span class="line"> <span class="comment">// 期望首次render完成之后再请求数据</span></span><br><span class="line"> setTimeout((): <span class="function"><span class="params">void</span> =></span> {</span><br><span class="line"> request();</span><br><span class="line"> }, <span class="number">200</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (action) {</span><br><span class="line"> action();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">let</span> willFocusSubscription: NavigationEventSubscription | <span class="literal">null</span> = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">let</span> didFocusSubscription: NavigationEventSubscription | <span class="literal">null</span> = <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (willFocus && navigation) {</span><br><span class="line"> willFocusSubscription = navigation.addListener(<span class="string">'willFocus'</span>, (): <span class="function"><span class="params">void</span> =></span></span><br><span class="line"> willFocus()</span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (didFocus && navigation) {</span><br><span class="line"> didFocusSubscription = navigation.addListener(<span class="string">'didFocus'</span>, (): <span class="function"><span class="params">void</span> =></span></span><br><span class="line"> didFocus()</span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (): <span class="function"><span class="params">void</span> =></span> {</span><br><span class="line"> <span class="keyword">if</span> (willFocusSubscription) {</span><br><span class="line"> willFocusSubscription.remove();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (didFocusSubscription) {</span><br><span class="line"> didFocusSubscription.remove();</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"> }, []);</span><br><span class="line">};</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>接上一篇笔记,了解常用自定义Hooks的写法,能够手写简单Hook。</p>
<p>后续有常用的hook会整理在这里。</p>
<p>参考文章:<a href="https://blog.csdn.net/KlausLily/article/details/104586371" target="_blank" rel="noopener">https://blog.csdn.net/KlausLily/article/details/104586371</a></p>
</summary>
<category term="React" scheme="http://yoursite.com/categories/React/"/>
<category term="前端基础" scheme="http://yoursite.com/tags/%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title>React Hooks记录</title>
<link href="http://yoursite.com/2020/06/22/React%20Hooks%E8%AE%B0%E5%BD%95/"/>
<id>http://yoursite.com/2020/06/22/React Hooks记录/</id>
<published>2020-06-22T08:55:03.000Z</published>
<updated>2020-06-22T08:55:57.200Z</updated>
<content type="html"><![CDATA[<p>记录 React Hooks 学习情况,希望能通过记录的方式更深入地了解Hooks相关原理。主要内容来源:</p><p><a href="https://github.com/dt-fe/weekly/blob/v2/104.%E7%B2%BE%E8%AF%BB%E3%80%8AFunction%20Component%20%E5%85%A5%E9%97%A8%E3%80%8B.md" target="_blank" rel="noopener">https://github.com/dt-fe/weekly/blob/v2/104.%E7%B2%BE%E8%AF%BB%E3%80%8AFunction%20Component%20%E5%85%A5%E9%97%A8%E3%80%8B.md</a></p><p>Function Component 就是以 Function 的形式创建的 React 组件,Hooks 是辅助 Function Component 的工具。</p><a id="more"></a><h2 id="1-useState"><a href="#1-useState" class="headerlink" title="1.useState"></a>1.useState</h2><figure class="highlight javascript"><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"><span class="function"><span class="keyword">function</span> <span class="title">Counter</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> [count, setCount] = useState(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> log = <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> setCount(count + <span class="number">1</span>);</span><br><span class="line"> setTimeout(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(count);</span><br><span class="line"> }, <span class="number">3000</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"> <div></span><br><span class="line"> <p>You clicked {count} times<<span class="regexp">/p></span></span><br><span class="line"><span class="regexp"> <button onClick={log}>Click me</</span>button></span><br><span class="line"> <<span class="regexp">/div></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp">}</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">/</span><span class="regexp">/ 0 1 2</span></span><br></pre></td></tr></table></figure><p>state 是 Immutable 的(不可改变的)</p><p>Class Component:通过 this.state 读取 state,会导致每次代码执行都会去拿最新的 state 引用 // 3 3 3</p><p>Function Component:</p><p>通过数组第二个参数 Set 一个新值后,原来的值会形成一个新的引用在下次渲染时。<strong>(感觉应该是当前渲染?或者是新的值会形成一个新的引用在下次渲染时?)</strong></p><p>由于对 state 的读取没有通过 this.的方式,使得每次 setTimeout 都读取了当时渲染闭包环境的数据,虽然最新的值跟着最新的渲染变了,但旧的渲染里,状态依然是旧值。</p><p>共渲染四次(首次渲染+三次 setState,setTimeout 分别生效在 1、2、3 次渲染 → 对应 state 值 0、1、2)</p><figure class="highlight javascript"><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"><span class="keyword">const</span> [count, setCount] = useState(<span class="number">0</span>);</span><br><span class="line">setCount(<span class="function"><span class="params">c</span> =></span> c + <span class="number">1</span>); <span class="comment">// setCount的回调函数中,c值永远指向最新的count值</span></span><br></pre></td></tr></table></figure><h2 id="2-useRef"><a href="#2-useRef" class="headerlink" title="2.useRef"></a>2.useRef</h2><figure class="highlight javascript"><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"><span class="function"><span class="keyword">function</span> <span class="title">Counter</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> count = useRef(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> log = <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> count.current++;</span><br><span class="line"> setTimeout(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(count.current);</span><br><span class="line"> }, <span class="number">3000</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"> <div></span><br><span class="line"> <p>You clicked {count.current} times<<span class="regexp">/p></span></span><br><span class="line"><span class="regexp"> <button onClick={log}>Click me</</span>button></span><br><span class="line"> <<span class="regexp">/div></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp">}</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">/</span><span class="regexp">/ 3 3 3</span></span><br></pre></td></tr></table></figure><p><strong>通过 useRef 创建的对象,其值只有一份,而且在所有 Rerender 之间共享。</strong>对 count.current 赋值或读取,读到的永远是其最新值,而与渲染闭包无关</p><h2 id="3-useEffect"><a href="#3-useEffect" class="headerlink" title="3.useEffect"></a>3.useEffect</h2><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Counter</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> [count, setCount] = useState(<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">const</span> currentCount = useRef(count);</span><br><span class="line"></span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> currentCount.current = count;</span><br><span class="line"> });</span><br><span class="line"> <span class="comment">// 在每次渲染完毕后,将 count 此时最新的值赋给 currentCount.current,这样就使 currentCount 的值自动同步了 count 的最新值</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> log = <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> setCount(count + <span class="number">1</span>);</span><br><span class="line"> setTimeout(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(currentCount.current);</span><br><span class="line"> }, <span class="number">3000</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"> <div></span><br><span class="line"> <p>You clicked {count} times<<span class="regexp">/p></span></span><br><span class="line"><span class="regexp"> <button onClick={log}>Click me</</span>button></span><br><span class="line"> <<span class="regexp">/div></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp">}</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">/</span><span class="regexp">/ 3 3 3</span></span><br></pre></td></tr></table></figure><p>useEffect是处理副作用的,其执行时机在每次Render渲染完毕后。(每次渲染都会执行,只是实际在真实DOM操作完毕后??)</p><p>useEffect也随着每次渲染而不同的,同一个组件不同渲染之间,useEffect内闭包环境完全独立。对于本次的例子,useEffect 共执行了四次,经历了如下四次赋值最终变成3。 //0 1 2 3</p><p><strong>setTimeout的例子,三次点击触发了四次渲染,但setTimeout分别生效在第1、2、3次渲染中,因此值是0 1 2。</strong></p><p><strong>useEffect的例子中,三次点击也触发了四次渲染,但useEffect分别生效在第1、2、3、4次渲染中,最终使currentCount的值变成3</strong></p><p><em>自定义Hook包装useRef-简易自定义Hook</em></p><figure class="highlight javascript"><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 class="function"><span class="keyword">function</span> <span class="title">useCurrentValue</span>(<span class="params">value</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> ref = useRef(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> ref.current = value;</span><br><span class="line"> }, [value]);</span><br><span class="line"> <span class="comment">// 仅当 value 的值变化了,再将其最新值同步给 ref.current</span></span><br><span class="line"> <span class="keyword">return</span> ref;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>useEffect的第二个参数:dependences定义了useEffect的依赖,在新的渲染中,只要所有依赖项的引用都不发生变化,useEffect就不会被执行,且当依赖项为[]时,useEffect仅在初始化执行一次,后续的Rerender永远也不会被执行。</p><p><em>将setTimeout换成setInterval</em></p><figure class="highlight javascript"><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="function"><span class="keyword">function</span> <span class="title">Counter</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> [count, setCount] = useState(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="keyword">const</span> id = setInterval(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> setCount(count + <span class="number">1</span>); <span class="comment">// setCount(0 + 1) setInterval永远在第一次Render的闭包中-count值永远为0</span></span><br><span class="line"> }, <span class="number">1000</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="params">()</span> =></span> clearInterval(id);</span><br><span class="line"> }, []); <span class="comment">// [count] - 1 2 3...</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <h1>{count}</h1>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 1 1 1 1 1 ... 依赖count却填了空</span></span><br></pre></td></tr></table></figure><p>useEffect函数的返回值。它的返回值是一个函数,这个函数在useEffect即将重新执行时,会先执行上一次Rerender useEffect第一个回调的返回函数,再执行下一次渲染的useEffect第一个回调。如果useEffect 的第二个参数设置为了[],那么其返回函数只会在这个组件被销毁时执行。</p><p>useEffect 对业务的抽象非常方便,几个例子:</p><p>·依赖项是查询参数,那么 useEffect 内可以进行取数请求,那么只要查询参数变化了,列表就会自动取数刷新。注意我们将取数时机从触发端改成了接收端。</p><p>·当列表更新后,重新注册一遍拖拽响应事件。也是同理,依赖参数是列表,只要列表变化,拖拽响应就会重新初始化,这样我们可以放心的修改列表,而不用担心拖拽事件失效。</p><p>·只要数据流某个数据变化,页面标题就同步修改。同理,也不需要在每次数据变化时修改标题,而是通过 useEffect “监听” 数据的变化,这是一种 “控制反转” 的思维。</p><h2 id="4-useReducer"><a href="#4-useReducer" class="headerlink" title="4.useReducer"></a>4.useReducer</h2><figure class="highlight javascript"><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 class="keyword">const</span> [state, dispatch] = useReducer(reducer, initialState);</span><br><span class="line"></span><br><span class="line"><span class="comment">// reducer 定义</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">reducer</span>(<span class="params">state, action</span>) </span>{</span><br><span class="line"> <span class="keyword">switch</span> (action.type) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"increment"</span>:</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> ...state,</span><br><span class="line"> count: state.count + <span class="number">1</span></span><br><span class="line"> };</span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"> <span class="keyword">return</span> state;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">// 可通过dispatch({ type: 'increment' })实现state.count的自增</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Counter</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> [state, dispatch] = useReducer(reducer, initialState);</span><br><span class="line"> <span class="keyword">const</span> { count } = state;</span><br><span class="line"></span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="keyword">const</span> id = setInterval(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> dispatch({ <span class="attr">type</span>: <span class="string">"increment"</span> });</span><br><span class="line"> }, <span class="number">1000</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="params">()</span> =></span> clearInterval(id);</span><br><span class="line"> }, [dispatch]);</span><br><span class="line"> <span class="comment">// dispatch引用永远也不会变,只会执行一次</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <h1>{count}</h1>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>本质是让函数与数据解耦,函数只管发出指令,而不需要关心使用的数据被更新时,需要重新初始化自身。</p><h2 id="5-useCallBack"><a href="#5-useCallBack" class="headerlink" title="5.useCallBack"></a>5.useCallBack</h2><p>为了避免遗漏依赖,必须将函数写在useEffect内部 — 维护麻烦 — useCallBack</p><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Counter</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> [count, setCount] = useState(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> getFetchUrl = useCallback(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"https://v?query="</span> + count;</span><br><span class="line"> }, [count]);</span><br><span class="line"></span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> getFetchUrl();</span><br><span class="line"> }, [getFetchUrl]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <h1>{count}</h1>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>useCallback也有第二个参数-依赖项,我们将getFetchUrl函数的依赖项通过useCallback打包到新的getFetchUrl函数中,那么useEffect就只需要依赖getFetchUrl这个函数,就实现了对count的间接依赖。</p><p><em>将函数抽到组件外部</em></p><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">useFetch</span>(<span class="params">count, step</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> useCallback(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="keyword">const</span> url = <span class="string">"https://v/search?query="</span> + count + <span class="string">"&step="</span> + step;</span><br><span class="line"> }, [count, step]);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 调用</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Parent</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> [count, setCount] = useState(<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">const</span> [step, setStep] = useState(<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">const</span> [other, setOther] = useState(<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">const</span> fetch = useFetch(count, step); <span class="comment">// 封装了 useFetch</span></span><br><span class="line"></span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> fetch();</span><br><span class="line"> }, [fetch]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <button onClick={() => setCount(<span class="function"><span class="params">c</span> =></span> c + <span class="number">1</span>)}>setCount {count}<<span class="regexp">/button></span></span><br><span class="line"><span class="regexp"> <button onClick={() => setStep(c => c + 1)}>setStep {step}</</span>button></span><br><span class="line"> <button onClick={() => setOther(<span class="function"><span class="params">c</span> =></span> c + <span class="number">1</span>)}>setOther {other}<<span class="regexp">/button></span></span><br><span class="line"><span class="regexp"> </</span>div></span><br><span class="line"> );</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>性能问题</strong>:count与step都会频繁变化,每次变化就会导致useFetch中useCallback依赖的变化,进而导致重新生成函数。然而实际上这种函数是没必要每次都重新生成的,反复生成函数会造成大量性能损耗。</p><p><em>1.利用Ref保证耗时函数依赖不变</em> -依赖不变,直接拿current,改动成本较高</p><figure class="highlight javascript"><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="function"><span class="keyword">function</span> <span class="title">useFetch</span>(<span class="params">count, step</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> countRef = useRef(count);</span><br><span class="line"> <span class="keyword">const</span> stepRef = useRef(step);</span><br><span class="line"></span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> countRef.current = count;</span><br><span class="line"> stepRef.current = step;</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> useCallback(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="keyword">const</span> url =</span><br><span class="line"> <span class="string">"https://v/search?query="</span> + countRef.current + <span class="string">"&step="</span> + stepRef.current;</span><br><span class="line"> }, [countRef, stepRef]); <span class="comment">// 依赖不会变,却能每次拿到最新的值</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><em>2.通用的自定义Hooks解决函数重新实例化问题</em></p><p>可以利用useRef创造一个自定义Hook代替useCallback,使其依赖的值变化时,回调不会重新执行,却能拿到最新的值。</p><figure class="highlight javascript"><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="function"><span class="keyword">function</span> <span class="title">useEventCallback</span>(<span class="params">fn, dependencies</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> ref = useRef(<span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 当fn回调函数变化时,ref.current重新指向最新的fn这个逻辑中规中矩。重点是,当依赖dependencies变化时,也重新为ref.current赋值,此时fn内部的dependencies值是最新的</span></span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> ref.current = fn;</span><br><span class="line"> }, [fn, ...dependencies]);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 仅执行一次(ref引用不会改变),所以每次都可以返回dependencies是最新的fn,并且fn还不会重新执行</span></span><br><span class="line"> <span class="keyword">return</span> useCallback(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="keyword">const</span> fn = ref.current;</span><br><span class="line"> <span class="keyword">return</span> fn();</span><br><span class="line"> }, [ref]);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>假设我们对useEventCallback传入的回调函数称为X,则这段代码的含义,就是使每次渲染的闭包中,回调函数X拿到的总是最新Rerender闭包中的那个,所以依赖的值永远是最新的,而且函数不会重新初始化。</strong></p><p>对于这种场景,也可以利用useReducer,将函数通过dispatch中调用(官方不推荐useEventCallback)</p><h2 id="6-useMemo-amp-amp-memo"><a href="#6-useMemo-amp-amp-memo" class="headerlink" title="6.useMemo && memo"></a>6.useMemo && memo</h2><p>React.memo等价于ClassComponent的PureComponent,使用memo包裹的组件,会在自身重渲染时,对每一个props项进行浅对比,如果引用没有变化,就不会触发重渲染。所以memo是一种很棒的性能优化工具。</p><figure class="highlight javascript"><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 class="keyword">const</span> Child = memo(<span class="function">(<span class="params">props</span>) =></span> {</span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> props.fetchData()</span><br><span class="line"> }, [props.fetchData])</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> )</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p><em>用useMemo做局部PureRender - 更细粒度的优化渲染</em></p><figure class="highlight javascript"><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 class="keyword">const</span> Child = <span class="function">(<span class="params">props</span>) =></span> {</span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> props.fetchData()</span><br><span class="line"> }, [props.fetchData])</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> useMemo(<span class="function"><span class="params">()</span> =></span> (</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> ), [props.fetchData])</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>利用useMemo包裹渲染代码,这样即便函数Child因为props的变化重新执行了,只要渲染函数用到的props.fetchData没有变,就不会重新渲染</p><h2 id="7-useContext"><a href="#7-useContext" class="headerlink" title="7.useContext"></a>7.useContext</h2><p>单独组件可以通过useMemo来优化,当程序复杂时,可能存在多个函数在所有Function Component间共享的情况,此时需要使用新Hook:useContext</p><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1.创建一个Context</span></span><br><span class="line"><span class="keyword">const</span> Store = createContext(<span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 2.在根节点使用Store.Provider注入</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Parent</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> [count, setCount] = useState(<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">const</span> [step, setStep] = useState(<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">const</span> fetchData = useFetch(count, step);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <Store.Provider value={{ setCount, setStep, fetchData }}></span><br><span class="line"> <Child /></span><br><span class="line"> <<span class="regexp">/Store.Provider></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp">}</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">/</span><span class="regexp">/ 3.在子节点使用useContext拿到注入的数据(value)</span></span><br><span class="line"><span class="regexp">const Child = memo((props) => {</span></span><br><span class="line"><span class="regexp"> const { setCount } = useContext(Store)</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp"> function onClick() {</span></span><br><span class="line"><span class="regexp"> setCount(count => count + 1)</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp"> return (</span></span><br><span class="line"><span class="regexp"> /</span><span class="regexp">/ ...</span></span><br><span class="line"><span class="regexp"> )</span></span><br><span class="line"><span class="regexp">})</span></span><br></pre></td></tr></table></figure><p>这样就不需要在每个函数间进行参数透传了,公共函数可以都放在Context里。但是当函数多了,Provider的value会变得很臃肿,我们可以结合之前讲到的useReducer解决这个问题。</p><p><em>使用useReducer为Context传递内容瘦身</em></p><p>使用useReducer,所有回调函数都通过调用dispatch完成,那么Context只要传递dispatch一个函数就好了。子节点全部通过dispatch去改变全局的state。</p><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> Store = createContext(<span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Parent</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> [state, dispatch] = useReducer(reducer, { <span class="attr">count</span>: <span class="number">0</span>, <span class="attr">step</span>: <span class="number">0</span> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <Store.Provider value={dispatch}></span><br><span class="line"> <Child /></span><br><span class="line"> <<span class="regexp">/Store.Provider></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp">}</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">const Child = useMemo((props) => {</span></span><br><span class="line"><span class="regexp"> const dispatch = useContext(Store)</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp"> function onClick() {</span></span><br><span class="line"><span class="regexp"> dispatch({</span></span><br><span class="line"><span class="regexp"> type: 'countInc'</span></span><br><span class="line"><span class="regexp"> })</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp"> return (</span></span><br><span class="line"><span class="regexp"> /</span><span class="regexp">/ ...</span></span><br><span class="line"><span class="regexp"> )</span></span><br><span class="line"><span class="regexp">})</span></span><br></pre></td></tr></table></figure><p><em>将state也放到Context中</em></p><p>稍稍改造下,将state也放到Context中,这下赋值与取值都非常方便了!</p><figure class="highlight javascript"><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 class="keyword">const</span> Store = createContext(<span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Parent</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> [state, dispatch] = useReducer(reducer, { <span class="attr">count</span>: <span class="number">0</span>, <span class="attr">step</span>: <span class="number">0</span> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <Store.Provider value={{ state, dispatch }}></span><br><span class="line"> <Count /></span><br><span class="line"> <Step /></span><br><span class="line"> <<span class="regexp">/Store.Provider></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp">}</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">/</span><span class="regexp">/ 不使用memo的原因:memo只能挡在最外层的,而通过useContext的数据注入发生在函数内部,会绕过memo,从而同时触发这两个组件的Rerender</span></span><br><span class="line"><span class="regexp">const Count = () => {</span></span><br><span class="line"><span class="regexp"> const { state, dispatch } = useContext(Store);</span></span><br><span class="line"><span class="regexp"> return useMemo(</span></span><br><span class="line"><span class="regexp"> () => (</span></span><br><span class="line"><span class="regexp"> <button onClick={() => dispatch("incCount")}></span></span><br><span class="line"><span class="regexp"> incCount {state.count}</span></span><br><span class="line"><span class="regexp"> </</span>button></span><br><span class="line"> ),</span><br><span class="line"> [state.count, dispatch]</span><br><span class="line"> );</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> Step = <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="keyword">const</span> { state, dispatch } = useContext(Store);</span><br><span class="line"> <span class="keyword">return</span> useMemo(</span><br><span class="line"> () => (</span><br><span class="line"> <button onClick={() => dispatch(<span class="string">"incStep"</span>)}>incStep {state.step}<<span class="regexp">/button></span></span><br><span class="line"><span class="regexp"> ),</span></span><br><span class="line"><span class="regexp"> [state.step, dispatch]</span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp">};</span></span><br></pre></td></tr></table></figure><p><strong>PS:当前开发的项目大致基于以上框架开发,并在此基础上用了一套action封装了所有需要使用的dispatch,可以在组件中直接调用action里的函数,直接改变state,防止出现重复的dispatch的情况</strong></p><h2 id="8-使用自定义Hook处理副作用"><a href="#8-使用自定义Hook处理副作用" class="headerlink" title="8.使用自定义Hook处理副作用"></a>8.使用自定义Hook处理副作用</h2><p>比如上面抛出的异步取数场景,在Function Component的最佳做法是封装成一个自定义Hook:</p><figure class="highlight javascript"><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><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> useDataApi = <span class="function">(<span class="params">initialUrl, initialData</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> [url, setUrl] = useState(initialUrl);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> [state, dispatch] = useReducer(dataFetchReducer, {</span><br><span class="line"> isLoading: <span class="literal">false</span>,</span><br><span class="line"> isError: <span class="literal">false</span>,</span><br><span class="line"> data: initialData</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="keyword">let</span> didCancel = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> fetchData = <span class="keyword">async</span> () => {</span><br><span class="line"> dispatch({ <span class="attr">type</span>: <span class="string">"FETCH_INIT"</span> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">const</span> result = <span class="keyword">await</span> axios(url);</span><br><span class="line"> <span class="keyword">if</span> (!didCancel) {</span><br><span class="line"> dispatch({ <span class="attr">type</span>: <span class="string">"FETCH_SUCCESS"</span>, <span class="attr">payload</span>: result.data });</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (error) {</span><br><span class="line"> <span class="keyword">if</span> (!didCancel) {</span><br><span class="line"> dispatch({ <span class="attr">type</span>: <span class="string">"FETCH_FAILURE"</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"> fetchData();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> didCancel = <span class="literal">true</span>;</span><br><span class="line"> };</span><br><span class="line"> }, [url]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> doFetch = <span class="function"><span class="params">url</span> =></span> setUrl(url);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> { ...state, doFetch };</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>可以看到,自定义Hook拥有完整生命周期,我们可以将取数过程封装起来,只暴露状态-是否在加载中:isLoading,是否取数失败:isError,数据:data。<br>使用情况如下,如果这个值需要存储到数据流,在所有组件之间共享,我们可以结合useEffect与useReducer:</p><figure class="highlight javascript"><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"><span class="function"><span class="keyword">function</span> <span class="title">App</span>(<span class="params">props</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> { dispatch } = useContext(Store);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> { data, isLoading, isError } = useDataApi(<span class="string">"https://v"</span>, {</span><br><span class="line"> showLog: <span class="literal">true</span></span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> dispatch({</span><br><span class="line"> type: <span class="string">"updateLoading"</span>,</span><br><span class="line"> data,</span><br><span class="line"> isLoading,</span><br><span class="line"> isError</span><br><span class="line"> });</span><br><span class="line"> }, [dispatch, data, isLoading, isError]);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="9-Others"><a href="#9-Others" class="headerlink" title="9.Others"></a>9.Others</h2><p><em>1.DefaultProps</em></p><p>对于 Function Component 的参数默认值,建议使用 React 内置方案解决,因为纯函数的方案不利于保持引用不变<br><figure class="highlight javascript"><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"><span class="keyword">const</span> Child = <span class="function">(<span class="params">{ type }</span>) =></span> {</span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="comment">// 不断刷新父元素,只会打印出一次日志</span></span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"type"</span>, type);</span><br><span class="line"> }, [type]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <div>Child</div>;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">Child.defaultProps = {</span><br><span class="line"> type: { <span class="attr">a</span>: <span class="number">1</span> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure></p><p><em>2.不要坑了子组件</em><br><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">App</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> [count, forceUpdate] = useState(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> schema = { <span class="attr">b</span>: <span class="number">1</span> };</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <Child schema={schema} /></span><br><span class="line"> <div onClick={() => forceUpdate(count + <span class="number">1</span>)}>Count {count}<<span class="regexp">/div></span></span><br><span class="line"><span class="regexp"> </</span>div></span><br><span class="line"> );</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> Child = memo(<span class="function"><span class="params">props</span> =></span> {</span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"schema"</span>, props.schema);</span><br><span class="line"> }, [props.schema]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <div>Child</div>;</span><br><span class="line">});</span><br></pre></td></tr></table></figure></p><p>只要父级props.schema变化就会打印日志。结果自然是,父组件每次刷新,子组件都会打印日志,也就是子组件[props.schema]完全失效了,因为引用一直在变化。</p><p>解法1:<br><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> Child = memo(<span class="function"><span class="params">props</span> =></span> {</span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"schema"</span>, props.schema);</span><br><span class="line"><span class="comment">// 子组件只关心值得变化</span></span><br><span class="line"> }, [<span class="built_in">JSON</span>.stringify(props.schema)]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <div>Child</div>;</span><br><span class="line">});</span><br></pre></td></tr></table></figure></p><p>解法2:<br><figure class="highlight javascript"><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"><span class="function"><span class="keyword">function</span> <span class="title">App</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> [count, forceUpdate] = useState(<span class="number">0</span>);</span><br><span class="line"> <span class="comment">// 利用Ref优化父组件 - 唯一引用</span></span><br><span class="line"> <span class="keyword">const</span> schema = useRef({ <span class="attr">b</span>: <span class="number">1</span> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <Child schema={schema.current} /></span><br><span class="line"> <div onClick={() => forceUpdate(count + <span class="number">1</span>)}>Count {count}<<span class="regexp">/div></span></span><br><span class="line"><span class="regexp"> </</span>div></span><br><span class="line"> );</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h2 id="10-Conclusion"><a href="#10-Conclusion" class="headerlink" title="10.Conclusion"></a>10.Conclusion</h2><p>以上是在重读(第n遍)这篇文章时做的记录,内容与文章可能没有太大出入,主要是想通过笔记的方式深入理解一哈Hooks,这一次阅读也了解了当前项目相关的Hook机制。<br>对于自定义Hook方面还不是特别了解(至少感觉自己手写写不粗来),会在下一篇笔记中记录常用的自定义Hook的实现~</p>]]></content>
<summary type="html">
<p>记录 React Hooks 学习情况,希望能通过记录的方式更深入地了解Hooks相关原理。主要内容来源:</p>
<p><a href="https://github.com/dt-fe/weekly/blob/v2/104.%E7%B2%BE%E8%AF%BB%E3%80%8AFunction%20Component%20%E5%85%A5%E9%97%A8%E3%80%8B.md" target="_blank" rel="noopener">https://github.com/dt-fe/weekly/blob/v2/104.%E7%B2%BE%E8%AF%BB%E3%80%8AFunction%20Component%20%E5%85%A5%E9%97%A8%E3%80%8B.md</a></p>
<p>Function Component 就是以 Function 的形式创建的 React 组件,Hooks 是辅助 Function Component 的工具。</p>
</summary>
<category term="React" scheme="http://yoursite.com/categories/React/"/>
<category term="前端基础" scheme="http://yoursite.com/tags/%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title>js奇奇怪怪的函数整理(不定时更新)(转载+整理)</title>
<link href="http://yoursite.com/2019/04/13/js%E5%A5%87%E5%A5%87%E6%80%AA%E6%80%AA%E7%9A%84%E5%87%BD%E6%95%B0%E6%95%B4%E7%90%86%EF%BC%88%E4%B8%8D%E5%AE%9A%E6%97%B6%E6%9B%B4%E6%96%B0%EF%BC%89%EF%BC%88%E8%BD%AC%E8%BD%BD+%E6%95%B4%E7%90%86%EF%BC%89/"/>
<id>http://yoursite.com/2019/04/13/js奇奇怪怪的函数整理(不定时更新)(转载+整理)/</id>
<published>2019-04-13T03:54:55.000Z</published>
<updated>2019-04-13T04:05:21.124Z</updated>
<content type="html"><![CDATA[<p>刷题或者开发中总会看到别人用过很多看起来特别高大上的函数方法(可能是我水平不够),这篇文章用来整理每次遇到的js函数,不定时更新,文中已标注转载位置。<br><a id="more"></a></p><h2 id="1-数组相关的函数"><a href="#1-数组相关的函数" class="headerlink" title="1.数组相关的函数"></a>1.数组相关的函数</h2><h3 id="1-1-some-和every"><a href="#1-1-some-和every" class="headerlink" title="1.1.some()和every()"></a>1.1.some()和every()</h3><p>every()与some()方法都是JS中数组的迭代方法。<br>some()是对数组中每一项运行给定函数,如果该函数对任一项返回true,则返回true。<br>every()是对数组中每一项运行给定函数,如果该函数对每一项返回true,则返回true。<br>some一直在找符合条件的值,一旦找到,则不会继续迭代下去。<br>every从迭代开始,一旦有一个不符合条件,则不会继续迭代下去。</p><figure class="highlight javascript"><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 class="keyword">var</span> arr = [ <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span> ]; </span><br><span class="line"><span class="built_in">console</span>.log( arr.some(<span class="function">(<span class="params"> item, index, array </span>)=></span>{ </span><br><span class="line"> <span class="built_in">console</span>.log( <span class="string">'item='</span> + item + <span class="string">',index='</span>+index+<span class="string">',array='</span>+array ); </span><br><span class="line"> <span class="keyword">return</span> item > <span class="number">3</span>; </span><br><span class="line">})); </span><br><span class="line"><span class="built_in">console</span>.log( arr.every(<span class="function">(<span class="params"> item, index, array </span>)=></span>{ </span><br><span class="line"> <span class="built_in">console</span>.log( <span class="string">'item='</span> + item + <span class="string">',index='</span>+index+<span class="string">',array='</span>+array ); </span><br><span class="line"> <span class="keyword">return</span> item > <span class="number">3</span>; </span><br><span class="line">}));</span><br></pre></td></tr></table></figure><p>运行结果<br><img src="/2019/04/13/js奇奇怪怪的函数整理(不定时更新)(转载+整理)/some&every.png" alt="some&every"><br>转自:<a href="https://blog.csdn.net/zhangjing0320/article/details/80677129" target="_blank" rel="noopener">https://blog.csdn.net/zhangjing0320/article/details/80677129</a></p>]]></content>
<summary type="html">
<p>刷题或者开发中总会看到别人用过很多看起来特别高大上的函数方法(可能是我水平不够),这篇文章用来整理每次遇到的js函数,不定时更新,文中已标注转载位置。<br></p>
</summary>
<category term="JavaScript" scheme="http://yoursite.com/categories/JavaScript/"/>
<category term="前端基础" scheme="http://yoursite.com/tags/%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title>js从数组中的对象取出特定字段并生成新的数组</title>
<link href="http://yoursite.com/2019/04/12/js%E4%BB%8E%E6%95%B0%E7%BB%84%E4%B8%AD%E7%9A%84%E5%AF%B9%E8%B1%A1%E5%8F%96%E5%87%BA%E7%89%B9%E5%AE%9A%E5%AD%97%E6%AE%B5%E5%B9%B6%E7%94%9F%E6%88%90%E6%96%B0%E7%9A%84%E6%95%B0%E7%BB%84/"/>
<id>http://yoursite.com/2019/04/12/js从数组中的对象取出特定字段并生成新的数组/</id>
<published>2019-04-12T12:58:09.000Z</published>
<updated>2019-04-12T13:02:21.793Z</updated>
<content type="html"><![CDATA[<figure class="highlight javascript"><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">var</span> arr = [</span><br><span class="line"> {</span><br><span class="line"> <span class="string">'id'</span>: <span class="string">'1'</span>,</span><br><span class="line"> <span class="string">'name'</span>: <span class="string">'img1'</span>,</span><br><span class="line"> <span class="string">'imgUrl'</span>: <span class="string">'./img1.jpg'</span>,</span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="string">'id'</span>: <span class="string">'2'</span>,</span><br><span class="line"> <span class="string">'name: '</span>img2<span class="string">',</span></span><br><span class="line"><span class="string"> '</span>imgUrl<span class="string">': '</span>./img2.jpg<span class="string">',</span></span><br><span class="line"><span class="string"> },</span></span><br><span class="line"><span class="string"> {</span></span><br><span class="line"><span class="string"> '</span>id<span class="string">': '</span><span class="number">3</span><span class="string">',</span></span><br><span class="line"><span class="string"> '</span>name<span class="string">': '</span>img3<span class="string">',</span></span><br><span class="line"><span class="string"> '</span>imgUrl<span class="string">': '</span>./img3.jpg<span class="string">',</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string">];</span></span><br><span class="line"><span class="string">arr.map(x => {return x.imgUrl}) // 生成数组</span></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span
</summary>
<category term="JavaScript" scheme="http://yoursite.com/categories/JavaScript/"/>
<category term="前端基础" scheme="http://yoursite.com/tags/%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title>解决div中嵌套元素时,二者点击事件同时触发</title>
<link href="http://yoursite.com/2019/04/12/%E8%A7%A3%E5%86%B3div%E4%B8%AD%E5%B5%8C%E5%A5%97%E5%85%83%E7%B4%A0%E6%97%B6%EF%BC%8C%E4%BA%8C%E8%80%85%E7%82%B9%E5%87%BB%E4%BA%8B%E4%BB%B6%E5%90%8C%E6%97%B6%E8%A7%A6%E5%8F%91/"/>
<id>http://yoursite.com/2019/04/12/解决div中嵌套元素时,二者点击事件同时触发/</id>
<published>2019-04-12T12:57:57.000Z</published>
<updated>2019-04-12T13:01:29.627Z</updated>
<content type="html"><![CDATA[<p>阻止JS冒泡事件~</p><p>以Angualr为例:</p><figure class="highlight html"><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></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"previewImg"</span> (<span class="attr">click</span>)=<span class="string">"closeImg()"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">img</span> <span class="attr">id</span>=<span class="string">"leftArrow"</span> *<span class="attr">ngIf</span>=<span class="string">"mid > left"</span> (<span class="attr">click</span>)=<span class="string">"leftImg($event)"</span> <span class="attr">src</span>=<span class="string">"../../../assets/community/leftArrow@3x.png"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">img</span> <span class="attr">id</span>=<span class="string">"pre"</span> <span class="attr">src</span>=<span class="string">"{{imageUrl}}"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">img</span> <span class="attr">id</span>=<span class="string">"rightArrow"</span> *<span class="attr">ngIf</span>=<span class="string">"mid < right"</span> (<span class="attr">click</span>)=<span class="string">"rightImg($event)"</span> <span class="attr">src</span>=<span class="string">"../../../assets/community/rightArrow@3x.png"</span>/></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure><a id="more"></a><p>点击left或right时同时会触发外层的closeImg()事件,此时需阻止JS的冒泡事件。</p><figure class="highlight javascript"><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">closeImg() {</span><br><span class="line"> <span class="keyword">this</span>.imageUrl = <span class="string">''</span>;</span><br><span class="line">}</span><br><span class="line">leftImg(e) {</span><br><span class="line"> alert(<span class="string">'left!'</span>);</span><br><span class="line"> e.stopPropagation();</span><br><span class="line">}</span><br><span class="line">rightImg(e) {</span><br><span class="line"> alert(<span class="string">'right!'</span>)</span><br><span class="line"> e.stopPropagation();</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>阻止JS冒泡事件~</p>
<p>以Angualr为例:</p>
<figure class="highlight html"><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"previewImg"</span> (<span class="attr">click</span>)=<span class="string">"closeImg()"</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">img</span> <span class="attr">id</span>=<span class="string">"leftArrow"</span> *<span class="attr">ngIf</span>=<span class="string">"mid &gt; left"</span> (<span class="attr">click</span>)=<span class="string">"leftImg($event)"</span> <span class="attr">src</span>=<span class="string">"../../../assets/community/leftArrow@3x.png"</span>/&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">img</span> <span class="attr">id</span>=<span class="string">"pre"</span> <span class="attr">src</span>=<span class="string">"&#123;&#123;imageUrl&#125;&#125;"</span>/&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">img</span> <span class="attr">id</span>=<span class="string">"rightArrow"</span> *<span class="attr">ngIf</span>=<span class="string">"mid &lt; right"</span> (<span class="attr">click</span>)=<span class="string">"rightImg($event)"</span> <span class="attr">src</span>=<span class="string">"../../../assets/community/rightArrow@3x.png"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
</summary>
<category term="JavaScript" scheme="http://yoursite.com/categories/JavaScript/"/>
<category term="前端基础" scheme="http://yoursite.com/tags/%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title>安卓手机端网页,开启输入法时页面内容被压缩的解决方法</title>
<link href="http://yoursite.com/2019/04/12/%E5%AE%89%E5%8D%93%E6%89%8B%E6%9C%BA%E7%AB%AF%E7%BD%91%E9%A1%B5%EF%BC%8C%E5%BC%80%E5%90%AF%E8%BE%93%E5%85%A5%E6%B3%95%E6%97%B6%E9%A1%B5%E9%9D%A2%E5%86%85%E5%AE%B9%E8%A2%AB%E5%8E%8B%E7%BC%A9%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95/"/>
<id>http://yoursite.com/2019/04/12/安卓手机端网页,开启输入法时页面内容被压缩的解决方法/</id>
<published>2019-04-12T12:53:56.000Z</published>
<updated>2019-04-12T12:56:37.267Z</updated>
<content type="html"><![CDATA[<p>在安卓手机端的网页中,打开输入框会使页面的整体内容压缩(可能因为我使用了百分比的布局)<br>而在iphone浏览网页时则不会出现这种问题。<br>对于这种情况需要添加部分js代码来防止页面的压缩。<br><a id="more"></a></p><figure class="highlight javascript"><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 class="keyword">var</span> h1 = $(<span class="string">'body'</span>).height();</span><br><span class="line"><span class="keyword">var</span> h2 = $(<span class="string">'#upMenu'</span>).height();</span><br><span class="line"><span class="keyword">var</span> h3 = $(<span class="string">'#main'</span>).height();</span><br><span class="line">$(<span class="built_in">window</span>).resize(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> $(<span class="string">'body'</span>).height(h1);</span><br><span class="line"> $(<span class="string">'#upMenu'</span>).height(h2);</span><br><span class="line"> $(<span class="string">'#main'</span>).height(h3);</span><br><span class="line"> $(<span class="string">'#main'</span>).css(<span class="string">'top'</span>, h2);</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p>我的页面是由upmenu和main两部分构成。<br>具体原理是当浏览器窗口大小发生变化时调用函数$(window).resize,让输入法打开后的页面的body高度等于输入法打开前的页面的body高度,<br>其他页面中的元素根据其定位方式去设置height或top、margin-top等样式即可。</p>]]></content>
<summary type="html">
<p>在安卓手机端的网页中,打开输入框会使页面的整体内容压缩(可能因为我使用了百分比的布局)<br>而在iphone浏览网页时则不会出现这种问题。<br>对于这种情况需要添加部分js代码来防止页面的压缩。<br></p>
</summary>
<category term="CSS" scheme="http://yoursite.com/categories/CSS/"/>
<category term="前端基础" scheme="http://yoursite.com/tags/%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title>手机端网页图片之间出现白线的解决方法</title>
<link href="http://yoursite.com/2019/04/12/%E6%89%8B%E6%9C%BA%E7%AB%AF%E7%BD%91%E9%A1%B5%E5%9B%BE%E7%89%87%E4%B9%8B%E9%97%B4%E5%87%BA%E7%8E%B0%E7%99%BD%E7%BA%BF%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95/"/>
<id>http://yoursite.com/2019/04/12/手机端网页图片之间出现白线的解决方法/</id>
<published>2019-04-12T12:45:32.000Z</published>
<updated>2019-04-12T12:52:50.502Z</updated>
<content type="html"><![CDATA[<p>我开发的实际情况是一个纵向的图片的列表,每个img由div包裹,在手机段访问是图片之间会出现一条白线。<br>原因是:img默认是内联模块,需要将其设置为display: block;<br>当然div之间也不要有margin~<br><a id="more"></a><br> 如图为修改后的情况(修改前的情况找不到了<em>(:з)∠)</em>)</p><p> <img src="/2019/04/12/手机端网页图片之间出现白线的解决方法/imgBlock.png" alt="imgBlock"></p>]]></content>
<summary type="html">
<p>我开发的实际情况是一个纵向的图片的列表,每个img由div包裹,在手机段访问是图片之间会出现一条白线。<br>原因是:img默认是内联模块,需要将其设置为display: block;<br>当然div之间也不要有margin~<br></p>
</summary>
<category term="CSS" scheme="http://yoursite.com/categories/CSS/"/>
<category term="前端基础" scheme="http://yoursite.com/tags/%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/"/>
</entry>
</feed>