<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>金数据技术博客</title>
<subtitle>Jinshuju Tech Blog · Engineering notes from the Jinshuju team</subtitle>
<link href="https://tech.jinshuju.net/"/>
<link rel="self" href="https://tech.jinshuju.net/feed.xml"/>
<id>https://tech.jinshuju.net/</id>
<updated>2026-08-21T02:00:12Z</updated>
<entry>
<title>跨 site 加载 JS 的代价 —— Chrome 139+ 的一个默认行为，和我们为它付的两次学费</title>
<link href="https://tech.jinshuju.net/posts/20/"/>
<id>https://tech.jinshuju.net/posts/20/</id>
<published>2026-08-21T01:58:24Z</published>
<updated>2026-08-21T02:00:12Z</updated>
<author><name>flanker</name></author>
<category term="frontend"/>
<category term="React"/>
<category term="nextjs"/>
<content type="html">&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://github.com/jinshuju/tech-blog/issues/21&quot; data-hovercard-type=&quot;issue&quot; data-hovercard-url=&quot;/jinshuju/tech-blog/issues/21/hovercard&quot;&gt;English Version&lt;/a&gt;&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;TL;DR&lt;/h2&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;我们的系统内页面首次打开会白屏 2~3 秒，LCP 高达 4 秒多&lt;/li&gt;
&lt;li&gt;Root cause 是 Chrome 139 起默认开启的 &lt;code class=&quot;notranslate&quot;&gt;LowPriorityAsyncScriptExecution&lt;/code&gt;：它会&lt;strong&gt;延迟执行跨 site 的 async script&lt;/strong&gt;，最长可达 1 秒&lt;/li&gt;
&lt;li&gt;我们的网站在 jinshuju.net，JS chunk 在 jsjform.com 的 CDN 上，正好命中&lt;/li&gt;
&lt;li&gt;被延迟的 chunk 让 React hydration 的调度器轮次从几十次暴涨到十万次，主线程被脚本占满，scripting 长达 2 秒多&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;修复&lt;/strong&gt;：给 Next.js 的 JS chunk 都标记 &lt;code class=&quot;notranslate&quot;&gt;fetchpriority=&quot;high&quot;&lt;/code&gt;，即可绕过延迟执行&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;修复后对比（home 页面）：&lt;/p&gt;
&lt;markdown-accessiblity-table&gt;&lt;table role=&quot;table&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Scripting 时长&lt;/th&gt;
&lt;th&gt;LCP 时长&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;修复前&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;大于 2000ms&lt;/td&gt;
&lt;td&gt;~4s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;禁用该特性启动 Chrome&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~700ms&lt;/td&gt;
&lt;td&gt;~1.6 ~ 2s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;修复后（同一账号、同网络）&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~700ms&lt;/td&gt;
&lt;td&gt;~2s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/markdown-accessiblity-table&gt;
&lt;h2 dir=&quot;auto&quot;&gt;背景&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;金数据是一款在线表单工具的 SaaS 产品。我们刻意把&lt;strong&gt;系统内&lt;/strong&gt;（表单编辑、数据管理，跑在 jinshuju.net）和&lt;strong&gt;对外表单&lt;/strong&gt;（填写者访问的公开页面）隔离在不同的域名上，而整个 Next.js 应用的 JS chunk 统一从 jsjform.com 的 CDN 加载。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这个「网站域名 ≠ 静态资源域名」的组合，让我们在同一个坑里交了两次学费。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;1. 我们自己埋的坑&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;其实这个坑之前就踩到过一次。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;之前对外表单冷加载时会有 1 秒白屏，当时初步定位到是 cross-site JS 执行有性能问题，于是把 JS chunk 的域名&lt;strong&gt;改成了和对外表单一致的 jsjform.com&lt;/strong&gt;——对外表单变成了同 site 加载，问题解决。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;当时也记录了副作用：系统内的域名从此和 chunk 域名不一致了（jinshuju.net vs jsjform.com）。但当时的判断是：系统内用户只有一次冷启动，之后都是热缓存，影响不大。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这个判断后来被证明是错的——&lt;strong&gt;热缓存同样受影响&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;2. 系统内太慢了&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;随着功能增加，系统内的代码量越来越大。我们发现访问 home 页面，特别是冷启动时，会白屏 2~3 秒，体验极差。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;做了一轮 chunk 瘦身后，Chrome 调试仍然显示 scripting 耗时长达 2 秒多。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;此时想起了之前踩过的坑。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://raw.githubusercontent.com/jinshuju/tech-blog/main/assets/chrome-cross-site-js/trace-before.png&quot;&gt;&lt;img src=&quot;https://raw.githubusercontent.com/jinshuju/tech-blog/main/assets/chrome-cross-site-js/trace-before.png&quot; alt=&quot;修复前：LCP 4.28s，scripting 2242ms&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;3. 用 agent 协助定位&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;第一次踩坑时并没有定位到真正的 root cause，这次我们在 Claude 的协助下重新排查。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;Agent 用线上页面和 CDN，通过 CDP 做了控制变量测试——同一份 chunk，只改变加载它的网站域名：&lt;/p&gt;
&lt;markdown-accessiblity-table&gt;&lt;table role=&quot;table&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;网站域名&lt;/th&gt;
&lt;th&gt;与 chunk 的关系&lt;/th&gt;
&lt;th&gt;ScriptDuration 冷&lt;/th&gt;
&lt;th&gt;ScriptDuration 热&lt;/th&gt;
&lt;th&gt;调度器轮次 冷&lt;/th&gt;
&lt;th&gt;调度器轮次 热&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;notranslate&quot;&gt;im.jsjform.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;同 site&lt;/td&gt;
&lt;td&gt;241 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;51 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5,527&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;36&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;notranslate&quot;&gt;zz.jsjform.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;同 site&lt;/td&gt;
&lt;td&gt;260 ms&lt;/td&gt;
&lt;td&gt;48 ms&lt;/td&gt;
&lt;td&gt;6,710&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;notranslate&quot;&gt;im.jinshuju.net&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;跨 site&lt;/td&gt;
&lt;td&gt;2,997 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2,807 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;109,876&lt;/td&gt;
&lt;td&gt;98,487&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;notranslate&quot;&gt;im.jsjform-x.net&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;跨 site（不存在的域名）&lt;/td&gt;
&lt;td&gt;2,858 ms&lt;/td&gt;
&lt;td&gt;2,802 ms&lt;/td&gt;
&lt;td&gt;180,964&lt;/td&gt;
&lt;td&gt;98,373&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/markdown-accessiblity-table&gt;
&lt;p dir=&quot;auto&quot;&gt;不论冷热，跨 site 都是同 site 的 &lt;strong&gt;12~55 倍&lt;/strong&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;strong&gt;注意&lt;/strong&gt;：纯 JS script 不会有这个问题。&lt;strong&gt;它只在 React 协作式调度下被放大——被延迟的 chunk 让 hydration/Suspense 反复重试，调度轮次爆炸，才吃满了主线程。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;4. 和上次不同的测试结果&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;这个问题不只影响冷启动：&lt;strong&gt;有热缓存时，差距倍数反而更大&lt;/strong&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;所以对系统内用户来说，这是必须修复的问题。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;5. Root Cause&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;网络搜索没有找到任何相关的 issue 或文章。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;Claude 先排查了 8 个方向：进程隔离、V8 code cache、时钟精度与 &lt;code class=&quot;notranslate&quot;&gt;performance.now()&lt;/code&gt; 开销、MessageChannel RTT、裸 CPU 吞吐、H2 连接复用、字节数与压缩、资源域名白名单逻辑——都没有问题。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;然后通过对 Chrome 版本做二分，&lt;strong&gt;定位到问题从 Chrome 139 开始出现&lt;/strong&gt;。再通过源码分析，找到了 root cause：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;Chrome 139 起默认开启 Blink feature &lt;code class=&quot;notranslate&quot;&gt;kLowPriorityAsyncScriptExecution&lt;/code&gt;（&lt;code class=&quot;notranslate&quot;&gt;third_party/blink/common/features.cc&lt;/code&gt;）。这个特性会让 async script 延迟执行，最长可达 1 秒。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;它有几个关键参数：&lt;/p&gt;
&lt;markdown-accessiblity-table&gt;&lt;table role=&quot;table&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;参数&lt;/th&gt;
&lt;th&gt;默认值&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;notranslate&quot;&gt;cross_site_only&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;notranslate&quot;&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;只对跨 site 的 script 生效&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;notranslate&quot;&gt;main_frame_only&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;notranslate&quot;&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;只对主 frame 生效（iframe 不生效）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;notranslate&quot;&gt;exclude_non_parser_inserted&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;notranslate&quot;&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;动态插入的脚本，也同样延迟执行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;notranslate&quot;&gt;opt_out_high_fetch_priority_hint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;notranslate&quot;&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;notranslate&quot;&gt;fetchpriority=high&lt;/code&gt; &lt;strong&gt;可以 opt out（不延迟）&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/markdown-accessiblity-table&gt;
&lt;h2 dir=&quot;auto&quot;&gt;6. 方案一：换成同一个域名？&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;第一个解决方案，是让网站和 JS chunk 使用同一个域名。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;但这对我们很难：系统内和对外表单是刻意隔离在不同域名上的，而 Next.js 一个代码库只能配置一个 &lt;code class=&quot;notranslate&quot;&gt;assetPrefix&lt;/code&gt;。非要走这条路，就得把系统内和对外隔离成独立部署，或者用代理重写 HTML 返回值。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;代价太高，放弃。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;7. 方案二：让 chunk 带上 &lt;code class=&quot;notranslate&quot;&gt;fetchpriority=high&lt;/code&gt;&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;从 Chrome 源码看，&lt;code class=&quot;notranslate&quot;&gt;fetchpriority=high&lt;/code&gt; 可以让 script 完全绕过这个延迟机制。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;但 Next.js 的 chunk script 是框架内部生成的，没有暴露配置接口。所以这个方案需要&lt;strong&gt;给 Next.js 打 patch&lt;/strong&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;我们最终采取了这个方案。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;8. 打 patch&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;需要一个 patch 加一段运行时代码。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;第一，patch Next.js 的 runtime：在 &lt;code class=&quot;notranslate&quot;&gt;pushScriptImpl&lt;/code&gt; 向页面写入 script 时，判断是否是 chunk，自动添加 fetchPriority：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-ts&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-s1&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;/_next/static/chunks/&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;fetchPriority&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;pl-s1&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;fetchPriority&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&quot;high&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;第二，客户端侧，Turbopack 运行时 append script 时同样自动添加：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-ts&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;prioritizeNextChunkScript&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Node&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;node&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;HTMLScriptElement&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;pathname&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;NEXT_CHUNK_PATH&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;fetchPriority&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'high'&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-c&quot;&gt;// `src` reflects the raw attribute when it is not a parsable URL&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;node&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;上线后 view-source 可以看到 chunk script 都带上了 &lt;code class=&quot;notranslate&quot;&gt;fetchPriority=&quot;high&quot;&lt;/code&gt;：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://raw.githubusercontent.com/jinshuju/tech-blog/main/assets/chrome-cross-site-js/view-source-fetchpriority.png&quot;&gt;&lt;img src=&quot;https://raw.githubusercontent.com/jinshuju/tech-blog/main/assets/chrome-cross-site-js/view-source-fetchpriority.png&quot; alt=&quot;view-source：chunk 带上了 fetchPriority=high&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;修复后的效果（同一账号、同网络）：LCP 从 4 秒多降到约 2 秒，scripting 从 2 秒多降到约 500ms：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://raw.githubusercontent.com/jinshuju/tech-blog/main/assets/chrome-cross-site-js/trace-after.png&quot;&gt;&lt;img src=&quot;https://raw.githubusercontent.com/jinshuju/tech-blog/main/assets/chrome-cross-site-js/trace-after.png&quot; alt=&quot;修复后：LCP 2.25s，scripting 509ms&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;strong&gt;已知缺口&lt;/strong&gt;：React 的 bootstrapScript（&lt;code class=&quot;notranslate&quot;&gt;id=&quot;_R_&quot;&lt;/code&gt; 的那个）无法标记 fetchPriority，但对结果影响不大。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;9. 后续&lt;/h2&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;strong&gt;Patch 只是缓解，不是根治&lt;/strong&gt;。我们在考虑给 Next.js 提 PR，让 chunk script 的属性可以配置。&lt;/li&gt;
&lt;li&gt;继续给 chunk 瘦身——脚本执行总量降下来，对延迟调度的敏感度也会降低。&lt;/li&gt;
&lt;li&gt;未来升级 Next.js 时需要同步维护这个 patch。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 dir=&quot;auto&quot;&gt;写在最后&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;两次学费的教训：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;strong&gt;「网站域名 ≠ 静态资源域名」不再只是一个 DNS/缓存层面的决定&lt;/strong&gt;——浏览器开始基于 site 边界调整脚本执行优先级，这个组合会直接影响运行时性能&lt;/li&gt;
&lt;li&gt;性能问题的归因要做到 root cause 为止。第一次我们停在了「cross-site JS 执行慢」的现象层，选了一个恰好绕过问题的方案，于是在另一个域名组合上把坑重新踩了一遍&lt;/li&gt;
&lt;/ul&gt;</content>
</entry>
<entry>
<title>一个 Button，440 KB —— Server Component 里 import antd 的代价</title>
<link href="https://tech.jinshuju.net/posts/18/"/>
<id>https://tech.jinshuju.net/posts/18/</id>
<published>2026-08-20T08:14:06Z</published>
<updated>2026-08-20T08:14:47Z</updated>
<author><name>flanker</name></author>
<category term="frontend"/>
<category term="React"/>
<category term="nextjs"/>
<content type="html">&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://github.com/jinshuju/tech-blog/issues/19&quot; data-hovercard-type=&quot;issue&quot; data-hovercard-url=&quot;/jinshuju/tech-blog/issues/19/hovercard&quot;&gt;English Version&lt;/a&gt;&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;TL;DR&lt;/h2&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;在 Next.js 的 &lt;strong&gt;Server Component&lt;/strong&gt; 里直接 &lt;code class=&quot;notranslate&quot;&gt;import { X } from 'antd'&lt;/code&gt;，会把&lt;strong&gt;整个 antd&lt;/strong&gt;（全部 76 个组件目录）打进这个路由的 JS bundle&lt;/li&gt;
&lt;li&gt;即便配置了 &lt;code class=&quot;notranslate&quot;&gt;experimental.optimizePackageImports&lt;/code&gt; 也无效&lt;/li&gt;
&lt;li&gt;修复方式：把 &lt;code class=&quot;notranslate&quot;&gt;import { X } from 'antd'&lt;/code&gt; 挪进 &lt;strong&gt;Client Component&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 dir=&quot;auto&quot;&gt;背景&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;金数据的新版前端是一个体量不小的 Next.js 应用，系统内页面的 UI 组件库用的是 antd。最近在做 bundle size 优化时我们发现：有些路由明明只用了一两个 antd 组件，产物里却出现了完整的 antd。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;排查下来，源头是一行看起来毫无问题的代码——在 Server Component 里 import 了 antd。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;最小复现&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;创建两个 Next.js 项目（antd 6.2.0 / Next.js 16.2.6 / React 19.2.1），只渲染一个 Button 按钮。&lt;/p&gt;
&lt;h3 dir=&quot;auto&quot;&gt;A. Server Import&lt;/h3&gt;
&lt;div class=&quot;highlight highlight-source-tsx&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;// app/page.tsx（Server Component）&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Button&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'antd'&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Page&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Button&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;primary&quot;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;hello&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 dir=&quot;auto&quot;&gt;B. Client Import&lt;/h3&gt;
&lt;div class=&quot;highlight highlight-source-tsx&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;// app/page.tsx（Server Component）&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;ClientButton&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'./ClientButton'&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Page&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;ClientButton&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-c&quot;&gt;// app/ClientButton.tsx&lt;/span&gt;

&lt;span class=&quot;pl-s&quot;&gt;'use client'&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Button&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'antd'&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;ClientButton&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Button&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;primary&quot;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;hello&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;两个页面实际渲染出的 HTML 一字不差：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-text-html-basic&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;button&lt;/span&gt;&quot; &lt;span class=&quot;pl-c1&quot;&gt;class&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;ant-btn css-var-root ant-btn-primary ant-btn-color-primary ant-btn-variant-solid&lt;/span&gt;&quot;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;hello&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;但 JS bundle size 差别巨大：&lt;/p&gt;
&lt;markdown-accessiblity-table&gt;&lt;table role=&quot;table&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;A. Server Import&lt;/th&gt;
&lt;th&gt;B. Client Import&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JS Bundle (RAW)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1458 KB&lt;/td&gt;
&lt;td&gt;176 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JS Bundle (gzip)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;440 KB&lt;/td&gt;
&lt;td&gt;56 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;打进产物的 antd 组件目录&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;76 个&lt;/td&gt;
&lt;td&gt;12 个&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/markdown-accessiblity-table&gt;
&lt;h2 dir=&quot;auto&quot;&gt;开发环境的对比&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;Server Import：54 个请求，5486 KB，&lt;code class=&quot;notranslate&quot;&gt;steps&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;table&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;transfer&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;upload&lt;/code&gt;…… 页面里根本不存在的组件全都被加载了。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://raw.githubusercontent.com/jinshuju/tech-blog/main/assets/antd-server-import/dev-server.png&quot;&gt;&lt;img src=&quot;https://raw.githubusercontent.com/jinshuju/tech-blog/main/assets/antd-server-import/dev-server.png&quot; alt=&quot;dev server import&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;Client Import：23 个请求，4446 KB（开发模式未压缩），没有多余的组件。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://raw.githubusercontent.com/jinshuju/tech-blog/main/assets/antd-server-import/dev-client.png&quot;&gt;&lt;img src=&quot;https://raw.githubusercontent.com/jinshuju/tech-blog/main/assets/antd-server-import/dev-client.png&quot; alt=&quot;dev client import&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;Production Bundle 分析对比&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;Server Import：All Route Modules 3.54 MB（压缩前），1545 个模块，包含所有 antd 组件。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://raw.githubusercontent.com/jinshuju/tech-blog/main/assets/antd-server-import/prod-server.png&quot;&gt;&lt;img src=&quot;https://raw.githubusercontent.com/jinshuju/tech-blog/main/assets/antd-server-import/prod-server.png&quot; alt=&quot;prod server import&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;Client Import：All Route Modules 1.05 MB（压缩前），365 个模块，仅包含 Button 和必须的 antd 依赖。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://raw.githubusercontent.com/jinshuju/tech-blog/main/assets/antd-server-import/prod-client.png&quot;&gt;&lt;img src=&quot;https://raw.githubusercontent.com/jinshuju/tech-blog/main/assets/antd-server-import/prod-client.png&quot; alt=&quot;prod client import&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;为什么会这样&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;antd/es/index.js&lt;/code&gt; 的第一行是：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;use client&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;所以 antd 的桶文件（Barrel）本身就是一个 &lt;strong&gt;client module&lt;/strong&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;Server Component 一旦 import 它，Next.js 就会在 &lt;code class=&quot;notranslate&quot;&gt;antd/es/index.js&lt;/code&gt; 这个模块上建立 RSC client reference——整个 index.js 被当作一个 client 入口包裹进去，它 re-export 的 76 个组件全部成为可达代码。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;optimizePackageImports&lt;/code&gt; 的原理是把桶文件 import 改写成对具体子路径的 import，但在这里改写无法生效，整个 barrel 都进了产物。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这个问题不只属于 antd：任何桶文件顶部带 &lt;code class=&quot;notranslate&quot;&gt;&quot;use client&quot;&lt;/code&gt; 的组件库，在 Server Component 里整包 import 都会踩中同一个坑。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;怎么修&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;把 antd 的使用挪进一个 Client Component，页面 / layout 保持 Server Component。渲染结果完全一致，bundle 里只剩下真正用到的组件。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;在金数据的代码库里，我们把这条规则写进了架构约束：&lt;code class=&quot;notranslate&quot;&gt;app/&lt;/code&gt; 路由层禁止 import antd，antd 的配置（Provider、message / notification 等）统一放在 views 层的 client 组件里。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;其他方式&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;直接 deep import 也可以绕过桶文件：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-ts&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Button&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'antd/es/button'&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;但我们不推荐这个方式：&lt;code class=&quot;notranslate&quot;&gt;antd/es/button&lt;/code&gt; 不是公开 API，且不是所有组件都有对应的路径。&lt;/p&gt;</content>
</entry>
<entry>
<title>解决 GraphQL 类型膨胀问题，显著提升 Turbopack 构建速度</title>
<link href="https://tech.jinshuju.net/posts/16/"/>
<id>https://tech.jinshuju.net/posts/16/</id>
<published>2025-12-22T02:29:05Z</published>
<updated>2025-12-22T03:20:29Z</updated>
<author><name>flanker</name></author>
<category term="frontend"/>
<category term="nextjs"/>
<category term="GraphQL"/>
<content type="html">&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://github.com/jinshuju/tech-blog/issues/17&quot; data-hovercard-type=&quot;issue&quot; data-hovercard-url=&quot;/jinshuju/tech-blog/issues/17/hovercard&quot;&gt;English Version&lt;/a&gt;&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;背景&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;金数据是一款在线表单工具的 SaaS 产品。我们的后端基于 &lt;strong&gt;Ruby on Rails&lt;/strong&gt;，通过 &lt;strong&gt;GraphQL&lt;/strong&gt; 对外提供接口；前端则是一个体量不小的 &lt;strong&gt;Next.js&lt;/strong&gt; 应用。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;产品已经运行了十年，业务模型非常复杂。这也是我们选择 GraphQL 的核心原因之一：&lt;strong&gt;类型系统&lt;/strong&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;GraphQL 强制要求接口定义类型，配合前端的 TypeScript，仅靠类型检查，我们就能提前规避掉大量潜在问题。保守估计，仅在类型层面就减少了 90% 的低级 bug。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;另一个现实原因是：我们需要用&lt;strong&gt;同一套接口&lt;/strong&gt;同时服务多个前端形态——&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;legacy 旧版前端&lt;/li&gt;
&lt;li&gt;新版 Next.js 前端&lt;/li&gt;
&lt;li&gt;移动端 App&lt;/li&gt;
&lt;li&gt;Mobile Web&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;GraphQL 在这方面非常友好。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;当然，代价也很明显：&lt;br&gt;
我们的主前端仓库已经相当复杂，路由数量、代码规模都不小。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;Turbopack 带来的新问题&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;随着项目不断增长，Webpack 在本地开发时已经明显吃力了：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;修改一个文件，等待几十秒才能看到结果&lt;/li&gt;
&lt;li&gt;production build 经常需要 5～10 分钟&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;这对开发效率的打击非常直接。&lt;br&gt;
&lt;strong&gt;开发体验的核心，其实就是反馈速度。&lt;/strong&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;好消息是：&lt;br&gt;
我们最近升级到了 &lt;strong&gt;Next.js 16&lt;/strong&gt;，并正式切换到了 &lt;strong&gt;Turbopack&lt;/strong&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;整个切换过程出乎意料地顺利，而且效果非常明显：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;production build：1 分钟左右&lt;/li&gt;
&lt;li&gt;本地开发：修改后几秒内即可看到反馈&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;效率提升非常显著 👍&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;但紧接着，一个严重的问题出现了。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;“第一次请求要 70 秒？”&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;在本地开发时，当你&lt;strong&gt;第一次启动服务&lt;/strong&gt;，然后访问第一个页面，事情开始变得不对劲。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;非常慢。&lt;br&gt;
慢到离谱。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;$ pnpm dev

 ▲ Next.js 16.0.10 (Turbopack)

 ✓ Starting...
 ✓ Ready &lt;span class=&quot;pl-k&quot;&gt;in&lt;/span&gt; 2.7s
 ○ Compiling /home ...
 GET /home 200 &lt;span class=&quot;pl-k&quot;&gt;in&lt;/span&gt; 79s (compile: 78s, proxy.ts: 336ms, render: 1055ms)
 ○ Compiling /favorites ...
 GET /favorites 200 &lt;span class=&quot;pl-k&quot;&gt;in&lt;/span&gt; 5.4s (compile: 5.4s, proxy.ts: 9ms, render: 17ms)
 GET /home 200 &lt;span class=&quot;pl-k&quot;&gt;in&lt;/span&gt; 49ms (compile: 18ms, proxy.ts: 15ms, render: 17ms)&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;解释一下这段日志：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;服务启动只用了 2.7 秒&lt;/li&gt;
&lt;li&gt;第一次访问 &lt;code class=&quot;notranslate&quot;&gt;/home&lt;/code&gt;：编译耗时 78 秒&lt;/li&gt;
&lt;li&gt;第二个页面 &lt;code class=&quot;notranslate&quot;&gt;/favorites&lt;/code&gt;：5.4 秒&lt;/li&gt;
&lt;li&gt;再次访问 &lt;code class=&quot;notranslate&quot;&gt;/home&lt;/code&gt;：49 毫秒&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;也就是说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;只有第一次请求，慢得像卡死了一样。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;70 多秒。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;我一度不知道这段时间该干嘛：&lt;br&gt;
去冲杯咖啡？&lt;br&gt;
还是和同事对视沉默几秒？&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;第一次尝试：循环依赖&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;直觉告诉我，问题可能出在循环依赖上。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;我们并没有启用非常严格的 lint 规则，项目历史又很久，出现一些循环依赖并不奇怪。而在构建阶段，循环依赖对 compiler 来说，怎么看都不像一件好事。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;于是我用 &lt;code class=&quot;notranslate&quot;&gt;madge&lt;/code&gt; 扫了一下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;$ npx madge --circular --extensions ts,tsx src/

Processed 3722 files (27.8s) (1544 warnings)

✖ Found 302 circular dependencies&lt;span class=&quot;pl-k&quot;&gt;!&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;……&lt;br&gt;
三百多个。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这个结果说实话有点震撼。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;循环依赖本身就会让代码：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;可读性变差&lt;/li&gt;
&lt;li&gt;职责边界模糊&lt;/li&gt;
&lt;li&gt;维护成本上升&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;从工程角度讲，它们本来也该被清理。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;我们确实做了一轮拆分和重构，把 shared 代码抽离出来，重新梳理依赖方向。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;strong&gt;但结果是：对这个问题完全没有帮助。&lt;/strong&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;第一次 compile 的耗时，&lt;strong&gt;没有任何变化&lt;/strong&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;看起来，Turbopack 对循环依赖已经有了比较成熟的处理机制。&lt;br&gt;
循环依赖值得解决，但它不是这次性能问题的根源。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;第二次尝试：Turbopack Tracing&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;既然靠猜不行，那就上工具。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;Next.js 为 Turbopack 提供了官方的 tracing 能力：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://nextjs.org/docs/app/guides/local-development#turbopack-tracing&quot; rel=&quot;nofollow&quot;&gt;https://nextjs.org/docs/app/guides/local-development#turbopack-tracing&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;在本地启动时，加上一个环境变量即可：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;$ NEXT_TURBOPACK_TRACING=1 pnpm dev&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;再次访问 &lt;code class=&quot;notranslate&quot;&gt;/home&lt;/code&gt;，问题依旧——70 多秒。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;但这一次，Turbopack 会在本地生成一个 tracing 文件：&lt;code class=&quot;notranslate&quot;&gt;.next/dev/trace-turbopack&lt;/code&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这是一个二进制文件，不能直接查看。Next.js 提供了一个内部工具：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;$ npx next internal trace .next/dev/trace-turbopack&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;然后，通过浏览器访问：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://trace.nextjs.org/&quot; rel=&quot;nofollow&quot;&gt;https://trace.nextjs.org/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;（这个“本地起服务 + 在线 UI 查看本地 trace”的设计，老实说有点神奇 😂）&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;火焰图告诉了我们真相&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;在 tracing 页面中，把视图切换到 &lt;strong&gt;Span in Order&lt;/strong&gt;，你就能看到完整的编译火焰图。&lt;/p&gt;
&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://private-user-images.githubusercontent.com/109811/529049613-41176026-1d17-4cf3-a4d6-b2c265a692ce.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODcyODM4MDgsIm5iZiI6MTc4NzI4MzUwOCwicGF0aCI6Ii8xMDk4MTEvNTI5MDQ5NjEzLTQxMTc2MDI2LTFkMTctNGNmMy1hNGQ2LWIyYzI2NWE2OTJjZS5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYwODIxJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MDgyMVQwMzM4MjhaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT02NDgyMzZkZDBiMTcyMzg2NDUxOWMwYzdiNTI3M2NiMzg3YTI1MWU5Y2YyODc1MzE3MmE5OTVjZTY4Yjg3OTA1JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZyZXNwb25zZS1jb250ZW50LXR5cGU9aW1hZ2UlMkZwbmcifQ.9GdYzEqvs7YfeAxhY1vY1OcMmUbnpQ8W7AdIYhrvX_Q&quot;&gt;&lt;img width=&quot;1280&quot; height=&quot;727&quot; alt=&quot;Image&quot; src=&quot;https://private-user-images.githubusercontent.com/109811/529049613-41176026-1d17-4cf3-a4d6-b2c265a692ce.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODcyODM4MDgsIm5iZiI6MTc4NzI4MzUwOCwicGF0aCI6Ii8xMDk4MTEvNTI5MDQ5NjEzLTQxMTc2MDI2LTFkMTctNGNmMy1hNGQ2LWIyYzI2NWE2OTJjZS5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYwODIxJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MDgyMVQwMzM4MjhaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT02NDgyMzZkZDBiMTcyMzg2NDUxOWMwYzdiNTI3M2NiMzg3YTI1MWU5Y2YyODc1MzE3MmE5OTVjZTY4Yjg3OTA1JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZyZXNwb25zZS1jb250ZW50LXR5cGU9aW1hZ2UlMkZwbmcifQ.9GdYzEqvs7YfeAxhY1vY1OcMmUbnpQ8W7AdIYhrvX_Q&quot; style=&quot;max-width: 100%; height: auto; max-height: 727px;; aspect-ratio: 1280 / 727; background-color: var(--bgColor-muted); border-radius: 6px&quot; class=&quot;js-gh-image-fallback&quot;&gt;&lt;/a&gt;
&lt;p dir=&quot;auto&quot;&gt;问题立刻变得非常清晰：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;编译 /(shell)/(system)/(withHeader)/(dashboard)/home/page&lt;br&gt;
耗时 70.36 秒&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;继续点进去看详情：&lt;/p&gt;
&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://private-user-images.githubusercontent.com/109811/529049655-a8709622-f00c-4e4c-8dba-04a68d6068c7.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODcyODM4MDgsIm5iZiI6MTc4NzI4MzUwOCwicGF0aCI6Ii8xMDk4MTEvNTI5MDQ5NjU1LWE4NzA5NjIyLWYwMGMtNGU0Yy04ZGJhLTA0YTY4ZDYwNjhjNy5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYwODIxJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MDgyMVQwMzM4MjhaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT01MGMyOWU1NmUyNDk1MWZmY2FjNzg3NzMxZDAwZTA2MjIyYTI5ZWJmYTI1YWMxODkyMDc4ZThmOTA1ZWRiOWJjJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZyZXNwb25zZS1jb250ZW50LXR5cGU9aW1hZ2UlMkZwbmcifQ.AhPorgyV4NC7XBchUcqL3evjG9B1rMs7IyIooqGSFcM&quot;&gt;&lt;img width=&quot;1280&quot; height=&quot;700&quot; alt=&quot;Image&quot; src=&quot;https://private-user-images.githubusercontent.com/109811/529049655-a8709622-f00c-4e4c-8dba-04a68d6068c7.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODcyODM4MDgsIm5iZiI6MTc4NzI4MzUwOCwicGF0aCI6Ii8xMDk4MTEvNTI5MDQ5NjU1LWE4NzA5NjIyLWYwMGMtNGU0Yy04ZGJhLTA0YTY4ZDYwNjhjNy5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYwODIxJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MDgyMVQwMzM4MjhaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT01MGMyOWU1NmUyNDk1MWZmY2FjNzg3NzMxZDAwZTA2MjIyYTI5ZWJmYTI1YWMxODkyMDc4ZThmOTA1ZWRiOWJjJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZyZXNwb25zZS1jb250ZW50LXR5cGU9aW1hZ2UlMkZwbmcifQ.AhPorgyV4NC7XBchUcqL3evjG9B1rMs7IyIooqGSFcM&quot; style=&quot;max-width: 100%; height: auto; max-height: 700px;; aspect-ratio: 1280 / 700; background-color: var(--bgColor-muted); border-radius: 6px&quot; class=&quot;js-gh-image-fallback&quot;&gt;&lt;/a&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;峰值内存使用：20+ GB&lt;/li&gt;
&lt;li&gt;持久化占用：约 5 GB&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;进一步展开调用栈后，真正的“元凶”出现了。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;在最底部、最耗时的两个分支里：&lt;/p&gt;
&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://private-user-images.githubusercontent.com/109811/529049706-e62dfdfb-16e0-4d79-97a6-ce6e083e2984.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODcyODM4MDgsIm5iZiI6MTc4NzI4MzUwOCwicGF0aCI6Ii8xMDk4MTEvNTI5MDQ5NzA2LWU2MmRmZGZiLTE2ZTAtNGQ3OS05N2E2LWNlNmUwODNlMjk4NC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYwODIxJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MDgyMVQwMzM4MjhaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT0wZDVjZWQ2Njg0MThjZDk5NmEwOTg4Mzc3OTM4MmIzYTQxODEzZmFhYjZhODJhNGIzMDhiMjY3OGI0ODU2ZDg2JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZyZXNwb25zZS1jb250ZW50LXR5cGU9aW1hZ2UlMkZwbmcifQ.XYmoMqLlrj6imlb8dNydtnCVEt2vlkYmHyUcjNccU6U&quot;&gt;&lt;img width=&quot;1280&quot; height=&quot;685&quot; alt=&quot;Image&quot; src=&quot;https://private-user-images.githubusercontent.com/109811/529049706-e62dfdfb-16e0-4d79-97a6-ce6e083e2984.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODcyODM4MDgsIm5iZiI6MTc4NzI4MzUwOCwicGF0aCI6Ii8xMDk4MTEvNTI5MDQ5NzA2LWU2MmRmZGZiLTE2ZTAtNGQ3OS05N2E2LWNlNmUwODNlMjk4NC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYwODIxJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MDgyMVQwMzM4MjhaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT0wZDVjZWQ2Njg0MThjZDk5NmEwOTg4Mzc3OTM4MmIzYTQxODEzZmFhYjZhODJhNGIzMDhiMjY3OGI0ODU2ZDg2JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZyZXNwb25zZS1jb250ZW50LXR5cGU9aW1hZ2UlMkZwbmcifQ.XYmoMqLlrj6imlb8dNydtnCVEt2vlkYmHyUcjNccU6U&quot; style=&quot;max-width: 100%; height: auto; max-height: 685px;; aspect-ratio: 1280 / 685; background-color: var(--bgColor-muted); border-radius: 6px&quot; class=&quot;js-gh-image-fallback&quot;&gt;&lt;/a&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;ReduxProvider 在加载 domain.ts&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;其中：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;parse domain.ts&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;单次耗时 26 秒&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;执行了两次&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;光解析这个文件，就吃掉了 52 秒。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;domain.ts 到底是什么？&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;简单来说：&lt;br&gt;
&lt;code class=&quot;notranslate&quot;&gt;domain.ts&lt;/code&gt; 是我们通过 &lt;strong&gt;GraphQL Codegen&lt;/strong&gt; 自动生成的类型文件。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;我们希望前端能完整地使用 GraphQL 类型系统，让 TypeScript 的类型推导发挥最大价值，于是把 &lt;code class=&quot;notranslate&quot;&gt;所有生成的类型&lt;/code&gt; 都集中在了这个文件里。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;结构大概是这样：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-ts&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Form&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;string&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;string&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;createdAt&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;Date&lt;/span&gt;
  ...
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;string&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;string&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;email&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;string&lt;/span&gt;
  ...
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;乍一看没什么问题。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;直到我看了一眼文件大小：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;$ ls -la src/typings/domain.ts
14M Dec 16 10:33 src/typings/domain.ts&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;14MB。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;TypeScript 解析一个 14MB 的类型文件，耗时 26 秒，&lt;br&gt;
&lt;strong&gt;其实非常合理。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;为什么它会膨胀到这么大？&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;我们使用的 codegen 配置是这样的：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-yaml&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-ent&quot;&gt;schema&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;http://localhost:3000/graphql&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot;&gt;documents&lt;/span&gt;:
  - &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;src/lib/api/graphql/**/*.graphql&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot;&gt;generates&lt;/span&gt;:
  &lt;span class=&quot;pl-ent&quot;&gt;src/typings/domain.ts&lt;/span&gt;:
    &lt;span class=&quot;pl-ent&quot;&gt;plugins&lt;/span&gt;:
      - &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;typescript&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
      - &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;typescript-operations&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;简单解释一下这两个插件的区别：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;typescript&lt;/code&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;根据 GraphQL schema&lt;/li&gt;
&lt;li&gt;生成完整的类型定义&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;typescript-operations&lt;/code&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;根据前端实际使用的 query / mutation&lt;/li&gt;
&lt;li&gt;生成精确到字段级别的返回类型&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;理论上，这是一个很合理、也很常见的组合。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;举个例子，假如你定义了一个 &lt;code class=&quot;notranslate&quot;&gt;Form&lt;/code&gt; 类型&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-graphql&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-en&quot;&gt;Form&lt;/span&gt; {
  &lt;span class=&quot;pl-v&quot;&gt;id&lt;/span&gt;
  &lt;span class=&quot;pl-v&quot;&gt;title&lt;/span&gt;
  &lt;span class=&quot;pl-v&quot;&gt;createdAt&lt;/span&gt;
}&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;然后你的前端，有一个 query，仅仅获取 Form 的基本信息：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-graphql&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;GetForm&lt;/span&gt; {
  &lt;span class=&quot;pl-v&quot;&gt;form&lt;/span&gt; {
    &lt;span class=&quot;pl-v&quot;&gt;id&lt;/span&gt;
    &lt;span class=&quot;pl-v&quot;&gt;title&lt;/span&gt;
  }
}&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;这种情况下，&lt;code class=&quot;notranslate&quot;&gt;typescript&lt;/code&gt; 会根据 schema 来生成一个 Form 类型，包含所有 schema 的定义：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-ts&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;export &lt;span class=&quot;pl-k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Form&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;string&lt;/span&gt;
  title: &lt;span class=&quot;pl-s1&quot;&gt;string&lt;/span&gt;
  createdAt: &lt;span class=&quot;pl-v&quot;&gt;Date&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;同时 &lt;code class=&quot;notranslate&quot;&gt;typescript-operations&lt;/code&gt; 会根据前端的 query，生成一个这个 query 实际用到的字段，对应的类型：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-ts&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;export &lt;span class=&quot;pl-k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;GetFormQuery&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;string&lt;/span&gt;
  title: &lt;span class=&quot;pl-s1&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;这样子的好处是提供了更准确的类型定义，因为你如果调用 GetForm，实际上返回的类型，并不是整个 Form，而是你在 query中显式获取的字段。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;我最初怀疑：&lt;br&gt;
是不是这两个插件一起用，导致了大量类型重复？&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;于是我尝试只保留 &lt;code class=&quot;notranslate&quot;&gt;typescript-operations&lt;/code&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;结果呢？&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;$ ls -la src/typings/domain.ts
13M Dec 16 11:14 src/typings/domain.ts&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;只小了一点点。&lt;br&gt;
显然，问题不在这里。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;真正的问题：Fragment 被“无限展开”了&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;直到我重新仔细看了一眼生成的 &lt;code class=&quot;notranslate&quot;&gt;domain.ts&lt;/code&gt;，才发现一个被忽略已久的细节：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;Fragment 的类型被完全 inline 展开了。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;在业务中，我们大量使用 Fragment 来复用字段，比如：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-graphql&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;fragment&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;FormBasic&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;Form&lt;/span&gt; {
  &lt;span class=&quot;pl-v&quot;&gt;id&lt;/span&gt;
  &lt;span class=&quot;pl-v&quot;&gt;title&lt;/span&gt;
  &lt;span class=&quot;pl-v&quot;&gt;createdAt&lt;/span&gt;
}&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;我们有 GetForm 这个 query，以及 CreateForm、UpdateForm 两个 mutation，他们都最终请求了 FormBasic 类型。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-graphql&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;GetForm&lt;/span&gt;(&lt;span class=&quot;pl-v&quot;&gt;$formToken&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;ID&lt;/span&gt;) {
  &lt;span class=&quot;pl-v&quot;&gt;form&lt;/span&gt;(&lt;span class=&quot;pl-v&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;$formToken&lt;/span&gt;) {
    &lt;span class=&quot;pl-k&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;FormBasic&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;...&lt;/span&gt;
  }
}

&lt;span class=&quot;pl-k&quot;&gt;mutation&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;CreateForm&lt;/span&gt;(&lt;span class=&quot;pl-v&quot;&gt;$input&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;CreateFormInput&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;!&lt;/span&gt;) {
  &lt;span class=&quot;pl-v&quot;&gt;createForm&lt;/span&gt;(&lt;span class=&quot;pl-v&quot;&gt;input&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;$input&lt;/span&gt;) {
    &lt;span class=&quot;pl-v&quot;&gt;form&lt;/span&gt; {
      &lt;span class=&quot;pl-k&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;FormBasic&lt;/span&gt;
      &lt;span class=&quot;pl-k&quot;&gt;...&lt;/span&gt;
    }
  }
}

&lt;span class=&quot;pl-k&quot;&gt;mutation&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;UpdateForm&lt;/span&gt;(&lt;span class=&quot;pl-v&quot;&gt;$input&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;UpdateFormInput&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;!&lt;/span&gt;) {
  &lt;span class=&quot;pl-v&quot;&gt;updateForm&lt;/span&gt;(&lt;span class=&quot;pl-v&quot;&gt;input&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;$input&lt;/span&gt;) {
    &lt;span class=&quot;pl-v&quot;&gt;form&lt;/span&gt; {
      &lt;span class=&quot;pl-k&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;FormBasic&lt;/span&gt;
      &lt;span class=&quot;pl-k&quot;&gt;...&lt;/span&gt;
    }
  }
}&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;但在生成的类型里，它们变成了这样：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-ts&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;export &lt;span class=&quot;pl-k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;GetFormQuery&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    id: &lt;span class=&quot;pl-s1&quot;&gt;string&lt;/span&gt;
    title: &lt;span class=&quot;pl-s1&quot;&gt;string&lt;/span&gt;
    createdAt: &lt;span class=&quot;pl-v&quot;&gt;Date&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

export &lt;span class=&quot;pl-k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;CreateFormMutation&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    id: &lt;span class=&quot;pl-s1&quot;&gt;string&lt;/span&gt;
    title: &lt;span class=&quot;pl-s1&quot;&gt;string&lt;/span&gt;
    createdAt: &lt;span class=&quot;pl-v&quot;&gt;Date&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

export &lt;span class=&quot;pl-k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;UpdateFormMutation&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    id: &lt;span class=&quot;pl-s1&quot;&gt;string&lt;/span&gt;
    title: &lt;span class=&quot;pl-s1&quot;&gt;string&lt;/span&gt;
    createdAt: &lt;span class=&quot;pl-v&quot;&gt;Date&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;strong&gt;每一个使用 Fragment 的地方，类型都被重新平铺了一遍。&lt;/strong&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;在一个业务复杂、字段很多、Fragment 被大量复用的系统里——&lt;br&gt;
这几乎注定会导致类型文件“爆炸”。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;解决方案：inlineFragmentTypes = combine&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;GraphQL Codegen 其实早就考虑到了这个问题。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;在文档里，我找到了这个配置项：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://the-guild.dev/graphql/codegen/plugins/typescript/typescript-operations#inlinefragmenttypes&quot; rel=&quot;nofollow&quot;&gt;https://the-guild.dev/graphql/codegen/plugins/typescript/typescript-operations#inlinefragmenttypes&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;highlight highlight-source-yaml&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-ent&quot;&gt;inlineFragmentTypes&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;combine&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;含义很直观：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;inline（默认）：Fragment 类型直接展开&lt;/li&gt;
&lt;li&gt;combine：复用 Fragment 类型引用&lt;/li&gt;
&lt;li&gt;mask：用于 Fragment Masking（这里不展开）&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;我们把配置改成这样：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-yaml&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-ent&quot;&gt;schema&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;http://localhost:3000/graphql&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot;&gt;documents&lt;/span&gt;:
  - &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;src/lib/api/graphql/**/*.graphql&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot;&gt;generates&lt;/span&gt;:
  &lt;span class=&quot;pl-ent&quot;&gt;src/typings/domain.ts&lt;/span&gt;:
    &lt;span class=&quot;pl-ent&quot;&gt;plugins&lt;/span&gt;:
      - &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;typescript-operations&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-ent&quot;&gt;config&lt;/span&gt;:
      &lt;span class=&quot;pl-ent&quot;&gt;inlineFragmentTypes&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;combine&lt;span class=&quot;pl-pds&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;重新生成类型文件。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;效果立竿见影&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;类型变成了我们真正想要的样子：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-ts&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;export &lt;span class=&quot;pl-k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;FormBasicFragment&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;string&lt;/span&gt;
  title: &lt;span class=&quot;pl-s1&quot;&gt;string&lt;/span&gt;
  createdAt: &lt;span class=&quot;pl-v&quot;&gt;Date&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;GetFormQuery&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;FormBasicFragment&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;CreateFormMutation&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;FormBasicFragment&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;UpdateFormMutation&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;FormBasicFragment&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;再看文件大小：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;$ ls -la src/typings/domain.ts
1.4M Dec 16 11:39 src/typings/domain.ts&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;strong&gt;14MB → 1.4MB&lt;/strong&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;十分之一。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;再次启动本地服务：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;GET /home 200 &lt;span class=&quot;pl-k&quot;&gt;in&lt;/span&gt; 17.1s (compile: 15.8s)&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;从 70 多秒，直接降到 17 秒。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;是的，17 秒依然不完美。&lt;br&gt;
但对于这样规模的项目来说，这已经是一个&lt;strong&gt;值得庆祝的进步&lt;/strong&gt; 🎉&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;而且在新的 Turbopack tracing 中，&lt;code class=&quot;notranslate&quot;&gt;parse domain.ts&lt;/code&gt; 已经不再是瓶颈。&lt;/p&gt;
&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://private-user-images.githubusercontent.com/109811/529049795-2d27ec7a-4220-4a8a-969b-e3117b985644.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODcyODM4MDgsIm5iZiI6MTc4NzI4MzUwOCwicGF0aCI6Ii8xMDk4MTEvNTI5MDQ5Nzk1LTJkMjdlYzdhLTQyMjAtNGE4YS05NjliLWUzMTE3Yjk4NTY0NC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYwODIxJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MDgyMVQwMzM4MjhaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT02NDI1NDE2NTU0MjFjZmYzYmEzNTkwODlmYzAyMTU3MGM2YWE0ZGNmNTM5NDgzNmMyNzRkYmVmNmYzMjFmNGE0JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZyZXNwb25zZS1jb250ZW50LXR5cGU9aW1hZ2UlMkZwbmcifQ.z9cqtmV-bSypiTi78BGa8Va9xmYOwf-eNRiTFv4M7Ys&quot;&gt;&lt;img width=&quot;1280&quot; height=&quot;727&quot; alt=&quot;Image&quot; src=&quot;https://private-user-images.githubusercontent.com/109811/529049795-2d27ec7a-4220-4a8a-969b-e3117b985644.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODcyODM4MDgsIm5iZiI6MTc4NzI4MzUwOCwicGF0aCI6Ii8xMDk4MTEvNTI5MDQ5Nzk1LTJkMjdlYzdhLTQyMjAtNGE4YS05NjliLWUzMTE3Yjk4NTY0NC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYwODIxJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MDgyMVQwMzM4MjhaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT02NDI1NDE2NTU0MjFjZmYzYmEzNTkwODlmYzAyMTU3MGM2YWE0ZGNmNTM5NDgzNmMyNzRkYmVmNmYzMjFmNGE0JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZyZXNwb25zZS1jb250ZW50LXR5cGU9aW1hZ2UlMkZwbmcifQ.z9cqtmV-bSypiTi78BGa8Va9xmYOwf-eNRiTFv4M7Ys&quot; style=&quot;max-width: 100%; height: auto; max-height: 727px;; aspect-ratio: 1280 / 727; background-color: var(--bgColor-muted); border-radius: 6px&quot; class=&quot;js-gh-image-fallback&quot;&gt;&lt;/a&gt;
&lt;h2 dir=&quot;auto&quot;&gt;后续与思考&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;这次优化：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;strong&gt;只改了一行配置&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;不影响任何运行时代码&lt;/li&gt;
&lt;li&gt;不影响业务逻辑&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;我们完整跑了一遍：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;lint&lt;/li&gt;
&lt;li&gt;type-check&lt;/li&gt;
&lt;li&gt;自动化测试&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;全部通过。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;值得一提的是，Codegen 文档里也明确说明：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;大多数情况下，&lt;code class=&quot;notranslate&quot;&gt;inline&lt;/code&gt; 是默认且更安全的选择。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;combine&lt;/code&gt; 在极深嵌套、复杂 list 类型下，可能会暴露出一些类型问题。&lt;br&gt;
我们会在后续继续观察、验证，并单独总结。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;但至少在当前的业务形态下，它解决了一个非常真实的问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;类型文件的无节制膨胀，正在拖慢构建系统。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 dir=&quot;auto&quot;&gt;总结&lt;/h2&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;复杂 GraphQL Schema + 默认 codegen 行为&lt;br&gt;
→ 生成了巨大的类型文件&lt;/li&gt;
&lt;li&gt;巨型 &lt;code class=&quot;notranslate&quot;&gt;domain.ts&lt;/code&gt;&lt;br&gt;
→ 成为 Turbopack 编译的性能瓶颈&lt;/li&gt;
&lt;li&gt;通过调整 &lt;code class=&quot;notranslate&quot;&gt;inlineFragmentTypes&lt;/code&gt;&lt;br&gt;
→ 类型文件体积下降 90%&lt;br&gt;
→ 本地首次编译时间显著缩短&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;strong&gt;这是一行配置，换来整个团队的开发体验提升。&lt;/strong&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;如果你的项目也遇到了类似的 Turbopack “第一次请求特别慢”的问题，&lt;br&gt;
不妨从这里检查一下。&lt;/p&gt;</content>
</entry>
<entry>
<title>Debug issues with legacy browser on macOS</title>
<link href="https://tech.jinshuju.net/posts/15/"/>
<id>https://tech.jinshuju.net/posts/15/</id>
<published>2024-01-21T14:54:28Z</published>
<updated>2024-01-21T14:55:34Z</updated>
<author><name>plrthink</name></author>
<category term="frontend"/>
<category term="build in public"/>
<content type="html">&lt;p dir=&quot;auto&quot;&gt;最近，我们在忙着打造全新的产品，金数据 5.0，将会给表单工具、业务系统搭建工具领域带来全新的行业标准。我们会陆陆续续分享在这个过程中的一些经验和故事。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;今天分享下我们是怎么在 macOS 上调试 iOS 11 Safari 的问题的。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;问题&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;非常不幸的是：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;XCode 15（macOS 14）是无法安装 iOS 11 的模拟器的&lt;/li&gt;
&lt;li&gt;我们运行着 iOS 11 的 iPhone 7 连接电脑后，无法调出 Safari 的开发者工具&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;除了使用 frpc + browserstack 这种方式外，我们还有什么办法可以调试 iOS 11 Safari 的问题呢？&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;解决方案&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;通过一番搜索，我们找到了一个解决方案：&lt;a href=&quot;https://inspect.dev&quot; rel=&quot;nofollow&quot;&gt;Inspect&lt;/a&gt;，他可以利用内置的 Chrome Devtool，来调试 iOS 11 Safari 的问题。相较于 &lt;a href=&quot;https://github.com/google/ios-webkit-debug-proxy&quot;&gt;ios-webkit-debug-proxy&lt;/a&gt;，Inspect 更加简单稳定。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;你的解决方案是什么？&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;你是怎么解决这类问题的呢？期待你的分享。&lt;/p&gt;</content>
</entry>
<entry>
<title>The guardian of Server Component in Next.js</title>
<link href="https://tech.jinshuju.net/posts/14/"/>
<id>https://tech.jinshuju.net/posts/14/</id>
<published>2023-12-23T07:41:48Z</published>
<updated>2024-01-21T15:01:39Z</updated>
<author><name>iwfan</name></author>
<category term="nextjs"/>
<category term="build in public"/>
<content type="html">&lt;p dir=&quot;auto&quot;&gt;在服务端开发中，鉴权、认证、校验等业务规则检查是不可或缺的，但当这些代码与 Server Component 结合时，我们应该如何更优雅地处理呢？🤔&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;通常最简单的处理方式就是通过增加 IF/ELSE 控制流来完成业务规则检查。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;DashboardPage&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;isUserLoggedIn&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;fetchUser&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  
  &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;isUserLoggedIn&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;redirect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'/login'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;canUseDashboard&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;queryFeatureFlag&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'dashboard'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  
  &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;canUseDashboard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;redirect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'/access-denied'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Dashboard&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;但当业务规则检查越来越多的时候，更恰当的方式是使用 &lt;a href=&quot;https://www.patterns.dev/react/presentational-container-pattern&quot; rel=&quot;nofollow&quot;&gt;Container Pattern&lt;/a&gt; ，通过分离关注点的方式，增强代码的可维护性。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;UserLoggedGuard&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; children &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;isUserLoggedIn&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;fetchUser&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  
  &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;isUserLoggedIn&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;redirect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'/login'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;children&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;CanUserDashbordGuard&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; children &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;canUseDashboard&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;queryFeatureFlag&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'dashboard'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  
  &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;canUseDashboard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;redirect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'/access-denied'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;children&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;DashboardPage&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;UserLoggedGuard&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;CanUserDashbordGuard&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Dashboard&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;CanUserDashbordGuard&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;UserLoggedGuard&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;但带来的另一个问题就是，一旦 Guard 组件过多，对业务组件 JSX 的侵入就变得很严重。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;DashboardPage&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;UserLoggedGuard&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;CanUserDashbordGuard&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;ParamsSafeGuard&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;ForbiddenAccessGuard&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Dashboard&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;ForbiddenAccessGuard&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;ParamsSafeGuard&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;CanUserDashbordGuard&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;UserLoggedGuard&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  )
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;看到上面的代码，你脑海里是否又响起了熟悉的“Hadoken!”  🫨&lt;br&gt;
&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://private-user-images.githubusercontent.com/28853200/292616199-14ec53fc-7a9d-47b9-8aa8-d6c35e41bac8.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODcyODM4MDgsIm5iZiI6MTc4NzI4MzUwOCwicGF0aCI6Ii8yODg1MzIwMC8yOTI2MTYxOTktMTRlYzUzZmMtN2E5ZC00N2I5LThhYTgtZDZjMzVlNDFiYWM4LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjA4MjElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwODIxVDAzMzgyOFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTdkZjhiMTBjYTdiNzU2NjllYmJlODU3NzU5MTMyMTc1NGFjOGFkNWQ5YzkzZDdjODBlMTc4YTZhYWQwMGRhMjQmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.CWvcwRtifjRSVwzXFNEL43E3kp_-eRxKCfLwO9V0lNY&quot;&gt;&lt;img src=&quot;https://private-user-images.githubusercontent.com/28853200/292616199-14ec53fc-7a9d-47b9-8aa8-d6c35e41bac8.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODcyODM4MDgsIm5iZiI6MTc4NzI4MzUwOCwicGF0aCI6Ii8yODg1MzIwMC8yOTI2MTYxOTktMTRlYzUzZmMtN2E5ZC00N2I5LThhYTgtZDZjMzVlNDFiYWM4LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjA4MjElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwODIxVDAzMzgyOFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTdkZjhiMTBjYTdiNzU2NjllYmJlODU3NzU5MTMyMTc1NGFjOGFkNWQ5YzkzZDdjODBlMTc4YTZhYWQwMGRhMjQmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.CWvcwRtifjRSVwzXFNEL43E3kp_-eRxKCfLwO9V0lNY&quot; alt=&quot;code-image-hadoken&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;br&gt;
此时为了避免 Guard 组件对业务组件的侵入，在设计上可以考虑根据 Server Component 的特性把这些 Guard 抽离出来，变成这样：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;DashboardPage&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Dashboard&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;composeGuard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;pl-v&quot;&gt;UserLoggedGuard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; 
  &lt;span class=&quot;pl-v&quot;&gt;CanUserDashbordGuard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; 
  &lt;span class=&quot;pl-v&quot;&gt;ParamsSafeGuard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-v&quot;&gt;ForbiddenAccessGuard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-v&quot;&gt;DashboardPage&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;现在看起来 Dashboard 的业务代码是不是更干净了？Guard 组件也更集中，方便统一查看检查规则。&lt;/p&gt;
&lt;hr&gt;
&lt;p dir=&quot;auto&quot;&gt;那 &lt;code class=&quot;notranslate&quot;&gt;composeGuard&lt;/code&gt; 要如何实现呢？在 Server Component 体系下，每个 Guard 都是一个独立的 Server Component，也是一个个的异步函数。想要实现这个逻辑也非常简单，就是把一堆异步函数放在一起，按顺序执行。我们可以按照这样的思路来实现：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;首先在 TS 中定义出来我们需要的类型：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-ts&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'react'&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;ParsedUrlQuery&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'node:querystring'&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;NextPageProps&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;params&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;NodeJS&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;Dict&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;searchParams&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;ParsedUrlQuery&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;children&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;ReactNode&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;NextPage&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;NextPageProps&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;JSX&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;Element&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;之后再来实现 compose 函数：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-ts&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;composeGuard&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;pl-s1&quot;&gt;guards&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;NextPage&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;NextPage&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;NextPageProps&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
     &lt;span class=&quot;pl-k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;guard&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;guards&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
         &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;guard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;💂 &lt;code class=&quot;notranslate&quot;&gt;composeGuard&lt;/code&gt; 现在的逻辑非常简单，就是生成一个新的 ServerComponent，然后在这个新生成的 Server Component 中逐个运行给定的 guard。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;但是 Bug 🐛 也非常明显，因为我们直接 return 了第一个 guard，导致现在 &lt;code class=&quot;notranslate&quot;&gt;composeGuard&lt;/code&gt; 的结果只会渲染出第一个 Component 💩。但我们期望的是 guard 在&lt;strong&gt;业务规则检查通过之后就运行后面的 Guard&lt;/strong&gt;，直到所有的 guard 都运行完为止。这里我们可以参考 Next.js 中 &lt;a href=&quot;https://github.com/vercel/next.js/blob/c5b5b1e3a3d85d498770a974c250c864e8d2a761/packages/next/src/client/components/not-found.ts#L9&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;notFound&lt;/code&gt;&lt;/a&gt;  和 &lt;a href=&quot;https://github.com/vercel/next.js/blob/c5b5b1e3a3d85d498770a974c250c864e8d2a761/packages/next/src/client/components/redirect.ts#L39&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;redirect&lt;/code&gt;&lt;/a&gt; 的 API 设计，通过抛异常来明确程序行为。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这里我们先定义出 &lt;code class=&quot;notranslate&quot;&gt;NextGuardError&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-ts&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;NextGuardError&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;nextGuard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;never&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;NextGuardError&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'go to next guard'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;isNextGuardError&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;error&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;error&lt;/span&gt; is &lt;span class=&quot;pl-smi&quot;&gt;NextGuardError&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;NextGuardError&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;之后再补全 &lt;code class=&quot;notranslate&quot;&gt;composeGuard&lt;/code&gt; 的代码逻辑：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-ts&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;ExtractNextPageProps&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;NextPage&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;NextPage&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;infer &lt;span class=&quot;pl-smi&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt; ? &lt;span class=&quot;pl-smi&quot;&gt;U&lt;/span&gt; : &lt;span class=&quot;pl-smi&quot;&gt;never&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;composeGuard&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;NextPage&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;...&lt;span class=&quot;pl-s1&quot;&gt;guards&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;ComposeGuardWrapper&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;: &lt;span class=&quot;pl-smi&quot;&gt;ExtractNextPageProps&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;guard&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;guards&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;guard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;isNextGuardError&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;pl-k&quot;&gt;continue&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;error&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;null&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;至此，我们的 &lt;code class=&quot;notranslate&quot;&gt;composeGuard&lt;/code&gt; 基本就已经写完了，使用起来也很简单。以&lt;code class=&quot;notranslate&quot;&gt;CanUserDashbordGuard&lt;/code&gt; 为例：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-ts&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;CanUserDashbordGuard&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; children &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;canUseDashboard&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;queryFeatureFlag&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'dashboard'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  
  &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;canUseDashboard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;redirect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'/access-denied'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;pl-en&quot;&gt;nextGuard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c&quot;&gt;// 逻辑检查通过之后，执行后续 guard&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;在业务逻辑检查中，如果不符合条件可以直接渲染 UI 告知用户，也可以使用 &lt;code class=&quot;notranslate&quot;&gt;notFound&lt;/code&gt; 或者 &lt;code class=&quot;notranslate&quot;&gt;redirect&lt;/code&gt; 跳转到其他的页面中。但逻辑检查通过之后，可以使用 &lt;code class=&quot;notranslate&quot;&gt;nextGuard&lt;/code&gt; 继续执行后续的 guard。&lt;/p&gt;
&lt;hr&gt;
&lt;p dir=&quot;auto&quot;&gt;回过头来再看一下之前的代码示例：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;DashboardPage&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Dashboard&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;composeGuard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;pl-v&quot;&gt;UserLoggedGuard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; 
  &lt;span class=&quot;pl-v&quot;&gt;CanUserDashbordGuard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; 
  &lt;span class=&quot;pl-v&quot;&gt;ParamsSafeGuard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-v&quot;&gt;ForbiddenAccessGuard&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-v&quot;&gt;DashboardPage&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;现在用户打开 Dashboard 页面时，会顺序经过 &lt;code class=&quot;notranslate&quot;&gt;UserLoggedGuard&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;CanUserDashbordGuard&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;ParamsSafeGuard&lt;/code&gt; 和 &lt;code class=&quot;notranslate&quot;&gt;ForbiddenAccessGuard&lt;/code&gt;。 但这些 guard 全部运行结束之后就会进入到 &lt;code class=&quot;notranslate&quot;&gt;DashboardPage&lt;/code&gt; 执行核心的业务逻辑。这样，通过 Server Component 守卫，我们能够更清晰、更优雅地组织和处理业务逻辑，使代码更易读、易维护。&lt;/p&gt;</content>
</entry>
<entry>
<title>技术人怎么有效地做沟通？</title>
<link href="https://tech.jinshuju.net/posts/13/"/>
<id>https://tech.jinshuju.net/posts/13/</id>
<published>2023-01-19T10:01:04Z</published>
<updated>2023-01-19T10:07:20Z</updated>
<author><name>plrthink</name></author>
<category term="communication"/>
<content type="html">&lt;p dir=&quot;auto&quot;&gt;作为一个与实现打交道的技术人，很容易在沟通中陷入细节，带来的结果就是有观点无法表述出来，丢失了沟通的目的，当然也增加了沟通的时间。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;分享我一直在实践的 tips，帮助大家更有效地做沟通。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;方法&lt;/h2&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;先说结论；如果是一个问题，那么先问问题。比如针对这个问题，我们有这么 2 个方案，需要大家来做决策。&lt;/li&gt;
&lt;li&gt;分层地做解释，注意，每层不超过 3 个观点，不超过 3 层。不然超过 3 个信息，人脑就很难记住了。&lt;/li&gt;
&lt;li&gt;层层递进&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;这些的理论基础其实就是结构化思维，当然这个理论适用的人群，覆盖的使用范围更广。更多内容推荐阅读『金字塔原理』这本书。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;当然，沟通前的准备，以及做沟通的心态同样不可忽视。准备就不说了，那更像是个 checklist，作为技术人一看就懂。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;心态&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;心态上，就是同理心，尤其是面向 PM，UX，甚至是用户时，摘掉我们工程师的帽子，想想他的知识领域是什么，想想他平时经常说什么。&lt;/p&gt;
&lt;hr&gt;
&lt;p dir=&quot;auto&quot;&gt;最后，回到最基础的 - Open Mind。&lt;/p&gt;</content>
</entry>
<entry>
<title>react-native 从 v0.61.4 升级到 v0.70.6 踩坑指南</title>
<link href="https://tech.jinshuju.net/posts/12/"/>
<id>https://tech.jinshuju.net/posts/12/</id>
<published>2022-12-13T03:49:04Z</published>
<updated>2023-01-28T07:15:43Z</updated>
<author><name>xianguoGou</name></author>
<category term="React Native"/>
<content type="html">&lt;h2 dir=&quot;auto&quot;&gt;需求背景&lt;/h2&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;目前，Cyborg项目中的react-native 已经很久都没有更新，还停留在&lt;code class=&quot;notranslate&quot;&gt;v0.61.4&lt;/code&gt;版本，而现在最新版本已经升级到&lt;code class=&quot;notranslate&quot;&gt;v0.70.6&lt;/code&gt;了；&lt;/li&gt;
&lt;li&gt;为了解决项目工程化配置（bundle、build）阶段，遇到的各种未知报错，和优化繁琐且复杂的启动流程；&lt;/li&gt;
&lt;li&gt;跟上时代步伐，与时俱进；享受react-native更新之后，带来的性能提升和用户体验；&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;例如，在之前的&lt;code class=&quot;notranslate&quot;&gt;react-native v0.61.4&lt;/code&gt;（历史版本）中， 当我们需要快速修复一个bug， 总是很苦恼在应用bundle或者build阶段，遇到有各种奇怪的问题，例如一个典型的 &lt;code class=&quot;notranslate&quot;&gt;sharp&lt;/code&gt;  :&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://user-images.githubusercontent.com/56954233/207365640-807ba537-dfce-4fde-afa0-ab65190c0352.png&quot;&gt;&lt;img width=&quot;740&quot; alt=&quot;企业微信截图_7fb05a3d-a832-4eef-8b7e-d8e630de2fd6&quot; src=&quot;https://user-images.githubusercontent.com/56954233/207365640-807ba537-dfce-4fde-afa0-ab65190c0352.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;当我们在构建发布版本时，遇到的这种类似的问题，其实和我们项目中用到的关系并不大，也就是我们所说的，其实并不关心这些，作为开发者，我们只需要关注业务/功能代码本身逻辑，其他的交给 RN 就好了，它会帮我们做&lt;code class=&quot;notranslate&quot;&gt;android&lt;/code&gt;和&lt;code class=&quot;notranslate&quot;&gt;ios&lt;/code&gt;平台兼容处理。可事实上？并不是这样。。。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;又或者在项目clone下来之后，&lt;code class=&quot;notranslate&quot;&gt;yarn install&lt;/code&gt; 安装失败就已经让你劝退了， 这又是什么原因？？？也许你会发现是node版本太高了，需要你降级到&lt;code class=&quot;notranslate&quot;&gt;node 14&lt;/code&gt;及以下版本，才能安装成功，是的，这又是sharp模块安装，需要低版本的node才能安装成功 。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;然而这些，只是暴露的部分已知的小问题，大多数都在版本迭代中修复了，这也是我们这次升级的目标之一，其次，由于开发者们所使用的机型、&lt;code class=&quot;notranslate&quot;&gt;mac&lt;/code&gt;系统，&lt;code class=&quot;notranslate&quot;&gt;Android Studio&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;Xcode&lt;/code&gt; 版本都不一致。导致问题出现的原因千奇百怪，这也是我们接下来需要探索和解决的问题。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;当然，最直接的原因就是换了mac M1之后，项目跑不起来了，果断升级！🤔🤔🤔&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;寻找解决方案&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;在我们一波分析之后，首先做的事情就是先升级&lt;code class=&quot;notranslate&quot;&gt; react-native&lt;/code&gt;，这里有一份帮助开发者升级的官方&lt;a href=&quot;https://github.com/react-native-community/upgrade-helper&quot;&gt;食用指南&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://user-images.githubusercontent.com/56954233/207375576-98690922-6aec-4039-a486-9341c6f6d152.png&quot;&gt;&lt;img width=&quot;1579&quot; alt=&quot;image&quot; src=&quot;https://user-images.githubusercontent.com/56954233/207375576-98690922-6aec-4039-a486-9341c6f6d152.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
它能帮助我们，在升级过程中清晰的知道，中间每个版本发生大的变化和更新。
&lt;p dir=&quot;auto&quot;&gt;在第一次尝试升级失败之后，再次发起挑战， 升级之前在&lt;code class=&quot;notranslate&quot;&gt;stackoverflow&lt;/code&gt;、 &lt;code class=&quot;notranslate&quot;&gt;github&lt;/code&gt;查阅相关资料，把前面各种尝试失败的经验记录下来。（千里之行，始于足下）&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;先升级&lt;code class=&quot;notranslate&quot;&gt;react-native&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;react&lt;/code&gt;版本，接着升级&lt;code class=&quot;notranslate&quot;&gt;babel&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;eslint&lt;/code&gt; 和&lt;code class=&quot;notranslate&quot;&gt;jest&lt;/code&gt;相关插件。按照helper文档一步步走，好了之后。先在&lt;code class=&quot;notranslate&quot;&gt;android studio&lt;/code&gt;  build一次，看有哪些问题（后面有记录）&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;过程中遇到的问题&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;一句话总结下来就是，第三方依赖包的更新和 gradle升级 以及修改第三方包升级之后语法不兼容的问题。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;值得一提的是，在react-native升级之后，由原来的JavaScriptCore更换成新的Hermes引擎，这次更换，用官方语言来总结一下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://hermesengine.dev/&quot; rel=&quot;nofollow&quot;&gt;Hermes&lt;/a&gt; is an open-source JavaScript engine optimized for React Native. For many apps, using Hermes will result in improved start-up time, decreased memory usage, and smaller app size when compared to JavaScriptCore. Hermes is used by default by React Native and no additional configuration is required to enable it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;简而言之，就是速度更快，体积更小。&lt;/p&gt;
&lt;h3 dir=&quot;auto&quot;&gt;其他依赖包主要的更新包括：&lt;/h3&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;jcore-react-native&lt;/code&gt; 处理RN升级之后，&lt;code class=&quot;notranslate&quot;&gt;ts&lt;/code&gt;和&lt;code class=&quot;notranslate&quot;&gt;lint&lt;/code&gt;语法报错问题&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;react-native-screens&lt;/code&gt; 处理RN升级之后，&lt;code class=&quot;notranslate&quot;&gt;ts&lt;/code&gt;和&lt;code class=&quot;notranslate&quot;&gt;lint&lt;/code&gt;语法报错问题&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;react-native-qrcode-svg&lt;/code&gt; 处理RN升级之后，&lt;code class=&quot;notranslate&quot;&gt;ts&lt;/code&gt;和&lt;code class=&quot;notranslate&quot;&gt;lint&lt;/code&gt;语法报错问题&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;react-native-reanimated&lt;/code&gt;， 解决应用启动之后的warning警告, &lt;a href=&quot;https://github.com/react-navigation/react-navigation/issues/9882&quot; data-hovercard-type=&quot;issue&quot; data-hovercard-url=&quot;/react-navigation/react-navigation/issues/9882/hovercard&quot;&gt;链接&lt;/a&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;在 &lt;code class=&quot;notranslate&quot;&gt;android studio&lt;/code&gt; build 成功之后，应用启动起来，算是长舒了一口气，可后面的问题，又在打包apk时，&lt;a href=&quot;https://github.com/facebook/react-native/issues/30761#issuecomment-763491895&quot; data-hovercard-type=&quot;issue&quot; data-hovercard-url=&quot;/react/react-native/issues/30761/hovercard&quot;&gt;问题&lt;/a&gt;发生了，花了半天时间排查。最后定位到问题原因是缺少一个bundle文件（由于一开始忽略了一个细节性错误，导致没找到问题所在，属实我的锅。）&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;👮👮👮 ： 测试过程中发现，某些android设备打开应用会出现闪退，例如 vivo、oppo机型。最后真机debug发现， &lt;code class=&quot;notranslate&quot;&gt;@sentry/react-native&lt;/code&gt; 包版本比较低，在android新版本机型上会出现语法不兼容的问题（&lt;a href=&quot;https://stackoverflow.com/questions/51610420/deprecated-gradle-features-were-used-in-this-build-making-it-incompatible-with&quot; rel=&quot;nofollow&quot;&gt;参考&lt;/a&gt;）。截图如下：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://user-images.githubusercontent.com/56954233/209799187-2f0ea129-7f93-47d5-9f9d-7df894dadb64.png&quot;&gt;&lt;img width=&quot;1050&quot; alt=&quot;image&quot; src=&quot;https://user-images.githubusercontent.com/56954233/209799187-2f0ea129-7f93-47d5-9f9d-7df894dadb64.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
解决方案：升级sentry版本` &quot;@sentry/react-native&quot;: &quot;^4.9.0&quot;`，最后build成功，测试一切正常。
&lt;p dir=&quot;auto&quot;&gt;问题记录：&lt;br&gt;
&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://user-images.githubusercontent.com/56954233/207891557-4f12773d-88d8-4f7c-bb51-98952458d11e.png&quot;&gt;&lt;img width=&quot;966&quot; alt=&quot;image&quot; src=&quot;https://user-images.githubusercontent.com/56954233/207891557-4f12773d-88d8-4f7c-bb51-98952458d11e.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;总结&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;问题大多数是在&lt;code class=&quot;notranslate&quot;&gt;build&lt;/code&gt;阶段遇到的，虽然说这次升级已经完成了，但后面还有一些第三方依赖还没来得及升级，如果感兴趣的同学，也可以顺便尝试一下，另外我们有些的库版本比较老了，现在有些已经不维护了，我们得找一些比较好的库替代，这也算是一个挑战。（路漫漫其修远兮，吾将上下而求索……）&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;参考资料&lt;/h2&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;a class=&quot;issue-link js-issue-link&quot; data-error-text=&quot;Failed to load title&quot; data-id=&quot;1139677342&quot; data-permission-text=&quot;Title is private&quot; data-url=&quot;https://github.com/react/react-native/issues/33120&quot; data-hovercard-type=&quot;issue&quot; data-hovercard-url=&quot;/react/react-native/issues/33120/hovercard&quot; href=&quot;https://github.com/react/react-native/issues/33120&quot;&gt;react/react-native#33120&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;issue-link js-issue-link&quot; data-error-text=&quot;Failed to load title&quot; data-id=&quot;973616426&quot; data-permission-text=&quot;Title is private&quot; data-url=&quot;https://github.com/react/react-native/issues/32037&quot; data-hovercard-type=&quot;issue&quot; data-hovercard-url=&quot;/react/react-native/issues/32037/hovercard&quot; href=&quot;https://github.com/react/react-native/issues/32037&quot;&gt;react/react-native#32037&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;issue-link js-issue-link&quot; data-error-text=&quot;Failed to load title&quot; data-id=&quot;577717383&quot; data-permission-text=&quot;Title is private&quot; data-url=&quot;https://github.com/oblador/react-native-animatable/issues/304&quot; data-hovercard-type=&quot;issue&quot; data-hovercard-url=&quot;/oblador/react-native-animatable/issues/304/hovercard&quot; href=&quot;https://github.com/oblador/react-native-animatable/issues/304&quot;&gt;oblador/react-native-animatable#304&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/facebook/react-native/issues/27840&quot; data-hovercard-type=&quot;issue&quot; data-hovercard-url=&quot;/react/react-native/issues/27840/hovercard&quot;&gt;[iOS] Build fails with error duplicate symbols for architecture x86_64 · Issue #27840 · facebook/react-native&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;issue-link js-issue-link&quot; data-error-text=&quot;Failed to load title&quot; data-id=&quot;369666361&quot; data-permission-text=&quot;Title is private&quot; data-url=&quot;https://github.com/crazycodeboy/react-native-splash-screen/issues/318&quot; data-hovercard-type=&quot;issue&quot; data-hovercard-url=&quot;/crazycodeboy/react-native-splash-screen/issues/318/hovercard&quot; href=&quot;https://github.com/crazycodeboy/react-native-splash-screen/issues/318&quot;&gt;crazycodeboy/react-native-splash-screen#318&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.weixin.qq.com/community/develop/doc/000c6275b68bf014265b30dc256800?_at=1670249635146&quot; rel=&quot;nofollow&quot;&gt;https://developers.weixin.qq.com/community/develop/doc/000c6275b68bf014265b30dc256800?_at=1670249635146&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;issue-link js-issue-link&quot; data-error-text=&quot;Failed to load title&quot; data-id=&quot;369666361&quot; data-permission-text=&quot;Title is private&quot; data-url=&quot;https://github.com/crazycodeboy/react-native-splash-screen/issues/318&quot; data-hovercard-type=&quot;issue&quot; data-hovercard-url=&quot;/crazycodeboy/react-native-splash-screen/issues/318/hovercard?comment_id=514362981&amp;amp;comment_type=issue_comment&quot; href=&quot;https://github.com/crazycodeboy/react-native-splash-screen/issues/318#issuecomment-514362981&quot;&gt;crazycodeboy/react-native-splash-screen#318 (comment)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;issue-link js-issue-link&quot; data-error-text=&quot;Failed to load title&quot; data-id=&quot;676233074&quot; data-permission-text=&quot;Title is private&quot; data-url=&quot;https://github.com/react/react-native/issues/29605&quot; data-hovercard-type=&quot;issue&quot; data-hovercard-url=&quot;/react/react-native/issues/29605/hovercard?comment_id=762354328&amp;amp;comment_type=issue_comment&quot; href=&quot;https://github.com/react/react-native/issues/29605#issuecomment-762354328&quot;&gt;react/react-native#29605 (comment)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;……&lt;/li&gt;
&lt;/ol&gt;</content>
</entry>
<entry>
<title>Draw tech diagrams clearly</title>
<link href="https://tech.jinshuju.net/posts/9/"/>
<id>https://tech.jinshuju.net/posts/9/</id>
<published>2022-09-14T13:40:24Z</published>
<updated>2022-09-15T01:25:46Z</updated>
<author><name>plrthink</name></author>
<category term="communication"/>
<content type="html">&lt;p dir=&quot;auto&quot;&gt;沟通永远都是件困难的事情，尤其是在技术问题上。即使是技术人员之间的表达，也会因为其复杂且抽象的特性，而变地异常的艰难。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;因此，我们大多数时候会选择将内容画出来，来辅助沟通的各方更容易地理解。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://user-images.githubusercontent.com/2429369/190169899-62375d8a-f217-460f-a9e1-2a2d49bc84fb.png&quot;&gt;&lt;img width=&quot;949&quot; alt=&quot;Screen Shot 2022-09-14 at 21 37 23&quot; src=&quot;https://user-images.githubusercontent.com/2429369/190169899-62375d8a-f217-460f-a9e1-2a2d49bc84fb.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;而如何清晰地、准确地可视化表达，也需要一定的技巧和原则：&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;整洁性&lt;/h2&gt;
&lt;h3 dir=&quot;auto&quot;&gt;清晰地书写&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;尤其是手写的时候，往往因为着急或不自信，写下的文字难以辨认，这反而增加了对方理解的难度。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;不要害怕慢，一笔一划地书写。&lt;/p&gt;
&lt;h3 dir=&quot;auto&quot;&gt;线条不要有交叉&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;否则当内容越来越多时，满屏的线条会像毛线球一样混乱。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;一致性&lt;/h2&gt;
&lt;h3 dir=&quot;auto&quot;&gt;颜色、图形&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;和代码一样，需要从始至终贯穿一样的风格。相同的模块使用相同的图形、颜色，有助于降低理解的复杂度。&lt;/p&gt;
&lt;h3 dir=&quot;auto&quot;&gt;箭头指向&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;这点尤为重要。在表达从属关系、数据流向时，箭头有助于我们表达方向。但我们也经常会因为不注意而前后表达不一致。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;解释性&lt;/h2&gt;
&lt;h3 dir=&quot;auto&quot;&gt;图例&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;我发现，这点更大的作用是时候再回看时，能够起到提醒的作用。不然我们很可能要重来一遍才能回忆起想要表达的信息。&lt;/p&gt;
&lt;hr&gt;
&lt;p dir=&quot;auto&quot;&gt;当然最重要的是，不要嫌麻烦，不要害怕。大胆地表达才是最重要的。&lt;/p&gt;</content>
</entry>
<entry>
<title>JavaScript 中与数字相关的奇怪问题</title>
<link href="https://tech.jinshuju.net/posts/8/"/>
<id>https://tech.jinshuju.net/posts/8/</id>
<published>2022-08-02T06:25:18Z</published>
<updated>2022-08-02T09:37:14Z</updated>
<author><name>emotionl</name></author>
<category term="JavaScript"/>
<content type="html">&lt;h2 dir=&quot;auto&quot;&gt;First of All&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;可以看下下面的几个问题然后给出自己的答案&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-smi&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;0.1&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;0.2&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;details&gt;
&lt;summary&gt;答案&lt;/summary&gt;
&lt;pre class=&quot;notranslate&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;0.30000000000000004
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;pre class=&quot;notranslate&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;console.log(parseInt(0.0000005))
&lt;/code&gt;&lt;/pre&gt;
&lt;details&gt;
&lt;summary&gt;答案&lt;/summary&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-en&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-smi&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;setTimeout First&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;2147483647&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;pl-en&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-smi&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;setTimeout Next&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;2147483648&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;details&gt;
&lt;summary&gt;答案&lt;/summary&gt;
&lt;pre class=&quot;notranslate&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;setTimeout Next
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p dir=&quot;auto&quot;&gt;如果你学习过前端八股文那么对 &lt;code class=&quot;notranslate&quot;&gt;0.1 + 0.2&lt;/code&gt; 这个问题应该都已经有了条件反射, 至少也能说个 IEEE-754, 但是后面这两个问题如果没有遇到过就只能挠头了.&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;Why&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;我们一个问题一个问题来看&lt;/p&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;0.1 + 0.2&lt;/code&gt;&lt;br&gt;
这个问题应该是出现频率比较高的了, 结论就是 0.1 与 0.2 用的二进制不能完美的表达出来, 只能根据精度舍入得到近似数, 而这两个近似数得到的也是一个近似数.&lt;br&gt;
需要说明的是这个问题并不是 JavaScript 独有, &lt;a href=&quot;https://0.30000000000000004.com/&quot; rel=&quot;nofollow&quot;&gt;Floating Point Math&lt;/a&gt; 展示了其他语言中 0.1 + 0.2 的结果.&lt;br&gt;
这个部分如果想深入理解可以参考 &lt;a href=&quot;https://mp.weixin.qq.com/s/EiT6BBKU6DdBWtemvvRztQ&quot; rel=&quot;nofollow&quot;&gt;为什么 0.1 + 0.2 = 0.300000004 ？&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;setTimeout(callback, 2147483647)&lt;/code&gt;&lt;br&gt;
这个问题其实能遇到的机率比较小, 因为在业务开发的时候很少会指定这么大的 timeout, 不过出于好奇可以了解这个边界在哪里.&lt;br&gt;
setTimeout 这个 API 使用一个 32 位的整数来存储其延迟值，所以任何高于这个值的东西都会引起问题&lt;br&gt;
PS: 32 位的证书中有 1 位表示符号, so 这个数为 &lt;code class=&quot;notranslate&quot;&gt;Math.pow(2, 32-1) - 1&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;parseInt(0.0000005)&lt;/code&gt;&lt;br&gt;
这个问题, 如果注意 parseInt 这个 API 参数的类型就能很好的避免了.&lt;br&gt;
parseInt 这个 API 接收的第一个参数的类型是 string. 如果传入的参数不是一个字符串，则将其转换为字符串 &lt;a href=&quot;https://262.ecma-international.org/6.0/#sec-tostring&quot; rel=&quot;nofollow&quot;&gt;(使用 ToString抽象操作)&lt;/a&gt;.&lt;br&gt;
在 number to string 的这个过程中, 如果出现以下两种情况则会用科学记数法表示&lt;/p&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;小于 1 且小数点后面带有 6 个 0 以上的浮点数值&lt;/li&gt;
&lt;li&gt;整数位数字多于 21 位&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=&quot;auto&quot;&gt;那么当你 &lt;code class=&quot;notranslate&quot;&gt;parseInt(0.0000005)&lt;/code&gt; 其实就是在 &lt;code class=&quot;notranslate&quot;&gt;parseInt('5e-7')&lt;/code&gt;, 而 &lt;code class=&quot;notranslate&quot;&gt;parseInt('5e-7')&lt;/code&gt; 会忽略掉 &lt;code class=&quot;notranslate&quot;&gt;'e-7'&lt;/code&gt;&lt;br&gt;
所以 &lt;code class=&quot;notranslate&quot;&gt;parseInt(0.0000005)&lt;/code&gt; 的结果为 &lt;code class=&quot;notranslate&quot;&gt;5&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 dir=&quot;auto&quot;&gt;So&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;在日常的 Coding 中如果碰到和数字相关的内容需要提高警惕&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;小数&lt;br&gt;
🌰：0.1、0.2&lt;/li&gt;
&lt;li&gt;特别大的数&lt;br&gt;
🌰：2147483648（2 的 32 次方减 1）&lt;/li&gt;
&lt;li&gt;数字的加减乘除&lt;br&gt;
🌰：0.1 + 0.2、1111.11 + 1111.11 + 1111.11 + 1111.11 + 1111.11&lt;/li&gt;
&lt;li&gt;调用某些 API 的时候需要注意参数的类型 , 避免隐式类型的转换&lt;br&gt;
🌰：parseInt(0.0000005)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 dir=&quot;auto&quot;&gt;And&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;本 Issue 会持续搜集 JavaScript 中与数字相关的奇怪问题 ~&lt;/p&gt;</content>
</entry>
<entry>
<title>CKEditor5食用指南</title>
<link href="https://tech.jinshuju.net/posts/7/"/>
<id>https://tech.jinshuju.net/posts/7/</id>
<published>2022-07-05T02:23:15Z</published>
<updated>2022-07-05T06:51:53Z</updated>
<author><name>BigBossTang</name></author>
<category term="frontend"/>
<category term="JavaScript"/>
<content type="html">&lt;h1 dir=&quot;auto&quot;&gt;CKEditor5简介&lt;/h1&gt;
&lt;p dir=&quot;auto&quot;&gt;CKEditor 5 可以提供任何&lt;strong&gt;WYSIWYG&lt;/strong&gt;（所见即所得）类型的编辑器。从类似于 Google Docs 和 Medium 的在线编辑器，到类似于 Slack 或 Twitter 的应用程序，CKEditor 5 编辑框架为每个用户提供了定制的和开箱即用的解决方案。这个具有 MVC 架构、自定义数据模型和虚拟 DOM 的现代 JavaScript 富文本编辑器是在 ES6 中重新开始编写的，具有出色的 webpack 支持。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;编辑器类型&lt;/h2&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/examples/builds/classic-editor.html&quot; rel=&quot;nofollow&quot;&gt;Classic Editor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/examples/builds/inline-editor.html&quot; rel=&quot;nofollow&quot;&gt;Inline Editor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/examples/builds/balloon-editor.html&quot; rel=&quot;nofollow&quot;&gt;Balloon Editor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/examples/builds/balloon-block-editor.html&quot; rel=&quot;nofollow&quot;&gt;Balloon Block Editor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/examples/builds/document-editor.html&quot; rel=&quot;nofollow&quot;&gt;Document Editor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 dir=&quot;auto&quot;&gt;引入方式&lt;/h2&gt;
&lt;h3 dir=&quot;auto&quot;&gt;官方&lt;/h3&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/ckeditor-5/online-builder/&quot; rel=&quot;nofollow&quot;&gt;在线创建&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/installation/getting-started/quick-start.html#building-the-editor-from-source&quot; rel=&quot;nofollow&quot;&gt;引入源码构建&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;优势：创建方便，能及时使用官方最新更新。&lt;br&gt;
缺陷：第一种的定制化程度不高，第二种配置复杂，且插件ck5相关的插件代码会耦合到应用项目里。&lt;/p&gt;
&lt;h3 dir=&quot;auto&quot;&gt;我们项目的引入方式&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;我们项目中使用，包括数据模型、插件交互、细节样式等都需要极高的定制化，且需要良好的代码隔离，理想方向是构建出来的ck5插件能用于我们的多个项目中且保持统一。&lt;br&gt;
上述两种方式都不能很好的满足我们的需求，于是我们进行了：&lt;/p&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;fork代码到&lt;a href=&quot;https://matrix.jinshuju.co/engineering/jinshuju/editorx&quot; rel=&quot;nofollow&quot;&gt;私有代码库&lt;/a&gt;&lt;br&gt;
在此仓库中进行各种定制化改造、自定义插件扩展、官方代码合并升级、打包发布等操作。&lt;/li&gt;
&lt;li&gt;发布到&lt;a href=&quot;https://npm.jinshuju.co/repository/jsjnpm/&quot; rel=&quot;nofollow&quot;&gt;私有依赖库&lt;/a&gt;&lt;br&gt;
在项目中通过依赖安装，将构建打包后的ck5引入项目之中进行使用。&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 dir=&quot;auto&quot;&gt;CKEditor5框架介绍&lt;/h1&gt;
&lt;p dir=&quot;auto&quot;&gt;由核心编辑器框架、编辑引擎、UI库组成&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;核心编辑器框架 &lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/framework/guides/architecture/core-editor-architecture.html&quot; rel=&quot;nofollow&quot;&gt;Core editor architecture&lt;/a&gt;&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/@ckeditor/ckeditor5-core&quot; rel=&quot;nofollow&quot;&gt;@ckeditor/ckeditor5-core&lt;/a&gt; ，由以下几个部分组成。&lt;/p&gt;
&lt;h3 dir=&quot;auto&quot;&gt;编辑器类 Editor Classes&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;该类&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html&quot; rel=&quot;nofollow&quot;&gt;Editor&lt;/a&gt;代表编辑器的基础。它是应用程序的入口点，粘合所有其他组件。它提供了一些您需要了解的属性：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#member-config&quot; rel=&quot;nofollow&quot;&gt;config&lt;/a&gt;– 配置对象。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#member-plugins&quot; rel=&quot;nofollow&quot;&gt;plugins&lt;/a&gt;和&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#member-commands&quot; rel=&quot;nofollow&quot;&gt;commands&lt;/a&gt;– 加载的插件和命令的集合。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#member-model&quot; rel=&quot;nofollow&quot;&gt;model&lt;/a&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/framework/guides/architecture/editing-engine.html#model&quot; rel=&quot;nofollow&quot;&gt;–编辑器数据模型&lt;/a&gt;的入口点。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#member-data&quot; rel=&quot;nofollow&quot;&gt;data&lt;/a&gt;– 数据控制器。它控制如何从文档中检索数据并在其中设置数据。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#member-editing&quot; rel=&quot;nofollow&quot;&gt;editing&lt;/a&gt;– 编辑控制器。它控制如何将模型呈现给用户进行编辑。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#member-keystrokes&quot; rel=&quot;nofollow&quot;&gt;keystrokes&lt;/a&gt;– 击键处理程序。它允许将击键绑定到动作。&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;除此之外，编辑器还公开了一些方法：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#static-function-create&quot; rel=&quot;nofollow&quot;&gt;create()&lt;/a&gt;– 静态create()方法。编辑器构造函数受到保护，您应该使用此静态方法创建编辑器。它允许初始化过程是异步的。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#function-destroy&quot; rel=&quot;nofollow&quot;&gt;destroy()&lt;/a&gt;– 销毁编辑器。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#function-execute&quot; rel=&quot;nofollow&quot;&gt;execute()&lt;/a&gt;– 执行给定的命令。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_utils_dataapimixin-DataApi.html#function-setData&quot; rel=&quot;nofollow&quot;&gt;setData()&lt;/a&gt;–&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_utils_dataapimixin-DataApi.html#function-getData&quot; rel=&quot;nofollow&quot;&gt;getData()&lt;/a&gt;一种从编辑器中检索数据并在编辑器中设置数据的方法。数据格式由&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_controller_datacontroller-DataController.html#member-processor&quot; rel=&quot;nofollow&quot;&gt;数据控制器的数据处理器控制&lt;/a&gt;，它不需要是字符串（如果您实现这样的&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_dataprocessor_dataprocessor-DataProcessor.html&quot; rel=&quot;nofollow&quot;&gt;数据处理器&lt;/a&gt;，它可以是例如 JSON ）。例如，请参阅如何&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/features/markdown.html&quot; rel=&quot;nofollow&quot;&gt;生成 Markdown 输出&lt;/a&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 dir=&quot;auto&quot;&gt;插件 &lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/framework/guides/architecture/core-editor-architecture.html#plugins&quot; rel=&quot;nofollow&quot;&gt;Plugins&lt;/a&gt;&lt;/h3&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;每个功能都由插件实现或至少启用。&lt;/li&gt;
&lt;li&gt;插件是高度精细的。&lt;/li&gt;
&lt;li&gt;插件对编辑器了如指掌。&lt;/li&gt;
&lt;li&gt;插件应该尽可能少地了解其他插件。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 dir=&quot;auto&quot;&gt;命令 Commands&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;命令是动作（回调）和状态（一组属性）的组合。&lt;br&gt;
所有命令都需要从&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_core_command-Command.html&quot; rel=&quot;nofollow&quot;&gt;Command&lt;/a&gt;类继承。需要将命令添加到编辑器的&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#member-commands&quot; rel=&quot;nofollow&quot;&gt;命令集合&lt;/a&gt;中，以便使用该&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#function-execute&quot; rel=&quot;nofollow&quot;&gt;Editor#execute()&lt;/a&gt;方法执行它们。&lt;br&gt;
示例：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;MyCommand&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Command&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-smi&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;MyPlugin&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Plugin&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;editor&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;pl-s1&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;commands&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'myCommand'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;MyCommand&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;editor&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;调用editor.execute( 'myCommand', 'Foo!' )将打印Foo!到控制台。&lt;/p&gt;
&lt;h3 dir=&quot;auto&quot;&gt;事件系统和可观察对象  &lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/framework/guides/architecture/core-editor-architecture.html#event-system-and-observables&quot; rel=&quot;nofollow&quot;&gt;Event system and observables&lt;/a&gt;&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;CKEditor 5 具有基于事件的架构，因此您可以在任何地方查找&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_utils_emittermixin-EmitterMixin.html&quot; rel=&quot;nofollow&quot;&gt;EmitterMixin&lt;/a&gt;和&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_utils_observablemixin-ObservableMixin.html&quot; rel=&quot;nofollow&quot;&gt;ObservableMixin&lt;/a&gt;混合。这两种机制都允许解耦代码并使其可扩展。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;大多数已经提到的类要么是发射器，要么是可观察的（可观察的也是发射器）。发射器可以发出（触发）事件并监听它们。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;MyPlugin&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Plugin&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-c&quot;&gt;// Make MyPlugin listen to someCommand#execute.&lt;/span&gt;
        &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;listenTo&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;someCommand&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'execute'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;pl-smi&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'someCommand was executed'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;pl-c&quot;&gt;// Make MyPlugin listen to someOtherCommand#execute and block it.&lt;/span&gt;
        &lt;span class=&quot;pl-c&quot;&gt;// You listen with a high priority to block the event before&lt;/span&gt;
        &lt;span class=&quot;pl-c&quot;&gt;// someOtherCommand's execute() method is called.&lt;/span&gt;
        &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;listenTo&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;someOtherCommand&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'execute'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;evt&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;pl-s1&quot;&gt;evt&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;priority&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;'high'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;pl-c&quot;&gt;// Inherited from Plugin:&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;destroy&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-c&quot;&gt;// Removes all listeners added with this.listenTo();&lt;/span&gt;
        &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;stopListening&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;第二个监听器'execute'展示了 CKEditor 5 代码中非常常见的做法之一。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;除了用事件装饰方法外，可观察对象还允许观察它们选择的属性。例如，Command该类通过调用使其成为#value可#isEnabled观察的&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/api/module_utils_observablemixin-ObservableMixin.html#function-set&quot; rel=&quot;nofollow&quot;&gt;set()&lt;/a&gt;：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Command&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'value'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'isEnabled'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-en&quot;&gt;mix&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;ObservableMixin&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-s1&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'change:value'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;evt&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;newValue&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;oldValue&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-smi&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;pl-s&quot;&gt;`&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-kos&quot;&gt;${&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;propertyName&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/span&gt; has changed from &lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-kos&quot;&gt;${&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;oldValue&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/span&gt; to &lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-kos&quot;&gt;${&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;newValue&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/span&gt;`&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;pl-s1&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;pl-c&quot;&gt;// -&amp;gt; 'value has changed from undefined to true'&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;Observables 还有一个被编辑器广泛使用的特性（尤其是在 UI 库中）——将一个对象的属性值绑定到其他一些属性的值或（一个或多个对象的）属性值的能力。当然，这也可以通过回调来处理。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;假设target和source是可观察的并且使用的属性是可观察的：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-s1&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'foo'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-s1&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-s1&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;pl-c&quot;&gt;// -&amp;gt; 1&lt;/span&gt;

&lt;span class=&quot;pl-c&quot;&gt;// Or:&lt;/span&gt;
&lt;span class=&quot;pl-s1&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'foo'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'bar'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-s1&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;bar&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-s1&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;pl-c&quot;&gt;// -&amp;gt; 1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 dir=&quot;auto&quot;&gt;编辑引擎 &lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/framework/guides/architecture/editing-engine.html&quot; rel=&quot;nofollow&quot;&gt;Editing engine&lt;/a&gt;&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/@ckeditor/ckeditor5-engine&quot; rel=&quot;nofollow&quot;&gt;@ckeditor/ckeditor5-engine&lt;/a&gt;&lt;/p&gt;
&lt;h3 dir=&quot;auto&quot;&gt;MVC架构&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/f39a5fb57885b3695b1bf83b6a532fbde99574c606af8acd130a85b9c22e714a/68747470733a2f2f636b656469746f722e636f6d2f646f63732f636b656469746f72352f6c61746573742f6173736574732f696d672f6672616d65776f726b2d6172636869746563747572652d656e67696e652d6469616772616d2e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/f39a5fb57885b3695b1bf83b6a532fbde99574c606af8acd130a85b9c22e714a/68747470733a2f2f636b656469746f722e636f6d2f646f63732f636b656469746f72352f6c61746573742f6173736574732f696d672f6672616d65776f726b2d6172636869746563747572652d656e67696e652d6469616772616d2e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://ckeditor.com/docs/ckeditor5/latest/assets/img/framework-architecture-engine-diagram.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;三层：模型、控制器和视图。有一个模型文档被&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/framework/guides/deep-dive/conversion/intro.html&quot; rel=&quot;nofollow&quot;&gt;转换&lt;/a&gt;为单独的视图——&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/framework/guides/architecture/editing-engine.html#editing-pipeline&quot; rel=&quot;nofollow&quot;&gt;编辑视图 Editing view&lt;/a&gt;和&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/framework/guides/architecture/editing-engine.html#data-pipeline&quot; rel=&quot;nofollow&quot;&gt;数据视图 Data view&lt;/a&gt;。这两个视图分别代表用户正在编辑的内容（您在浏览器中看到的 DOM 结构）和编辑器输入和输出数据（以插入的数据处理器可以理解的格式）。两个视图都具有虚拟 DOM 结构（自定义的类似 DOM 的结构），转换器和功能在其上工作，然后渲染到 DOM。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;绿色块是编辑器功能（插件）引入的代码。这些功能控制对模型进行哪些更改，如何将它们转换为视图以及如何根据触发的事件（视图和模型的事件）更改模型。&lt;br&gt;
由于此部分内容太多，接下来的内容只用部分实现代码来描述这三层， 详细文档请参阅&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/framework/guides/architecture/editing-engine.html&quot; rel=&quot;nofollow&quot;&gt;Editing engine&lt;/a&gt;&lt;/p&gt;
&lt;h3 dir=&quot;auto&quot;&gt;模型 Model&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;定义一个模型：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;schema&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-s1&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'stock'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;pl-c1&quot;&gt;allowWhere&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;'$text'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;pl-c1&quot;&gt;isInline&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;pl-c1&quot;&gt;isObject&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;pl-c1&quot;&gt;allowAttributes&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'code'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'type'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;在编辑器的model.schema中注册该模型， 包含了基础属性和接受的属性， 详细的属性含义参见&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/framework/guides/deep-dive/schema.html&quot; rel=&quot;nofollow&quot;&gt;schema文档&lt;/a&gt;&lt;/p&gt;
&lt;h3 dir=&quot;auto&quot;&gt;视图 View&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;分为编辑视图Editing view 和数据视图Data view。&lt;br&gt;
简单来说，编辑视图是编辑富文本时用户看到并可以编辑的 DOM。数据视图editor.getData()调用或editor.setData()得到或使用的富文本内容。&lt;/p&gt;
&lt;pre class=&quot;notranslate&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;editor.editing;                 // The editing pipeline (EditingController).
editor.editing.view;            // The editing view's controller.
editor.editing.view.document;   // The editing view's document.
editor.data;                    // The data pipeline (DataController).
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 dir=&quot;auto&quot;&gt;转换 Conversion&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;连接模型和视图。&lt;/p&gt;
&lt;h4 dir=&quot;auto&quot;&gt;数据向上转换&lt;/h4&gt;
&lt;hr&gt;
&lt;p dir=&quot;auto&quot;&gt;将数据加载到编辑器。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;// Data View -&amp;gt; Model&lt;/span&gt;
&lt;span class=&quot;pl-s1&quot;&gt;conversion&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'upcast'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;elementToElement&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;pl-c1&quot;&gt;view&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;pl-c1&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;'img'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;pl-c1&quot;&gt;attributes&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;pl-s&quot;&gt;'data-img-role'&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;'stock'&lt;/span&gt;
			&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;pl-en&quot;&gt;model&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;viewElement&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; writer &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;viewElement&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'data-stock-code'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;viewElement&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'data-stock-type'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;writer&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'stock'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
				code&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; type
			&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;pl-c&quot;&gt;// converterPriority: 'high'&lt;/span&gt;
	&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 dir=&quot;auto&quot;&gt;数据向下转换&lt;/h4&gt;
&lt;hr&gt;
&lt;p dir=&quot;auto&quot;&gt;从编辑器中检索数据。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;// Model -&amp;gt; Data view&lt;/span&gt;
&lt;span class=&quot;pl-s1&quot;&gt;conversion&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'dataDowncast'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;elementToElement&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;pl-c1&quot;&gt;model&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;'stock'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;pl-c1&quot;&gt;view&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;createStockView&lt;/span&gt;
	&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-c&quot;&gt;// Create view for data&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;createStockView&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;modelItem&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; writer &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;modelItem&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'code'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;modelItem&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'type'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'min'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;stockView&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;writer&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;createContainerElement&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'img'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;pl-s&quot;&gt;'data-img-role'&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;'stock'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;pl-s&quot;&gt;'data-stock-type'&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;pl-s&quot;&gt;'data-stock-code'&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;pl-c1&quot;&gt;src&lt;/span&gt;: &lt;span class=&quot;pl-en&quot;&gt;judgeSrc&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;stockView&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 dir=&quot;auto&quot;&gt;编辑向上转换&lt;/h4&gt;
&lt;hr&gt;
&lt;p dir=&quot;auto&quot;&gt;将编辑器内容呈现给用户进行编辑。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;// Model -&amp;gt; Editing View (element)&lt;/span&gt;
&lt;span class=&quot;pl-s1&quot;&gt;conversion&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'editingDowncast'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;elementToElement&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;pl-c1&quot;&gt;model&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;'stock'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;pl-en&quot;&gt;view&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;modelItem&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; writer &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;widgetElement&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;createStockEditingView&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;modelItem&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;writer&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;toWidget&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;widgetElement&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;writer&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'span'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-c&quot;&gt;// Create view for editor&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;createStockEditingView&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;modelItem&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;writer&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;stockCode&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;modelItem&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'code'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;modelItem&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'type'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'min'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;stockView&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;writer&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;createContainerElement&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'img'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;pl-c1&quot;&gt;src&lt;/span&gt;: &lt;span class=&quot;pl-en&quot;&gt;judgeSrc&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;stockCode&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;stockView&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;以上代码就简单实现了我们 data view -&amp;gt; model -&amp;gt; editing view -&amp;gt; data view 的转换， 更多的conversion内容请参阅&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/framework/guides/deep-dive/conversion/intro.html&quot; rel=&quot;nofollow&quot;&gt;conversion 文档&lt;/a&gt;&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;UI 库&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;CKEditor 5 的标准 UI 库是&lt;a href=&quot;https://www.npmjs.com/package/@ckeditor/ckeditor5-ui&quot; rel=&quot;nofollow&quot;&gt;@ckeditor/ckeditor5-ui&lt;/a&gt;. 它提供了允许构建与生态系统的其他组件无缝集成的模块化 UI 的基类和助手。详细的UI创建和通用UI组件请参阅&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/framework/guides/architecture/ui-library.html&quot; rel=&quot;nofollow&quot;&gt;UI library&lt;/a&gt;，这里只讲述几个通用组件的基础用法。&lt;br&gt;
使用 LabeledInputView 创建一个input：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;stockInputView&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;_createStockInput&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-en&quot;&gt;_createStockInput&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;locale&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;pl-c&quot;&gt;// Create equation input&lt;/span&gt;
		&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;stockInput&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;LabeledInputView&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;locale&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;InputTextView&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;inputView&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;stockInput&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;inputView&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;pl-s1&quot;&gt;stockInput&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;infoText&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'请输入股票代码'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;pl-c&quot;&gt;// 提示信息&lt;/span&gt;

		&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;onInput&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;inputView&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;element&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;stockInput&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;inputView&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

				&lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;saveButtonView&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;isEnabled&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;stockInput&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;pl-s1&quot;&gt;inputView&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'render'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;onInput&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;pl-s1&quot;&gt;inputView&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'input'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;onInput&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;stockInput&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;获取input的值&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;stockInputView&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;inputView&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;校验值、清空报错信息&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-en&quot;&gt;validate&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;maxLength&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;maxLength&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;stockInputView&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;errorText&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'代码长度不正确'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-en&quot;&gt;resetFormStatus&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;stockInputView&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;errorText&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;CKEditor5提供很好的UI规范，很多组件都可以直接拿来使用， 如果要自定义组件，请尽量遵循CKEditor5的设计规范，尽量使用CSS变量。&lt;/p&gt;
&lt;h1 dir=&quot;auto&quot;&gt;我们如何开发一个CKEditor5插件&lt;/h1&gt;
&lt;h2 dir=&quot;auto&quot;&gt;运行本地开发服务器&lt;/h2&gt;
&lt;pre class=&quot;notranslate&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;git clone git@matrix.jinshuju.co:engineering/jinshuju/editorx.git
cd editorx 
yarn
cd packages/ckeditors-build-classic
yarn start
&lt;/code&gt;&lt;/pre&gt;
&lt;p dir=&quot;auto&quot;&gt;tips: 在根目录安装依赖，避免插件版本冲突。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;文件结构&lt;/h2&gt;
&lt;pre class=&quot;notranslate&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;ckeditor5-xxx //xxx为插件名
│   README.md
│
└───docs //文档
│ 
│   
└───lang //多语言文件
│ 
│  
└───src
│   │ 
│   │   xxxediting.js //定义model 及转换
│   │   xxxcommand.js //定义command
│   │   xxxui.js //关联ui
│   │
│   └───view //视图文件
│     
│      
└───theme //样式文件、icons
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 dir=&quot;auto&quot;&gt;代码示例&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;点击查看&lt;a href=&quot;https://matrix.jinshuju.co/engineering/jinshuju/editorx/-/tree/dev/packages/ckeditor5-stock/src&quot; rel=&quot;nofollow&quot;&gt;项目代码&lt;/a&gt;或者&lt;a href=&quot;https://ckeditor.com/docs/ckeditor5/latest/framework/guides/plugins/creating-simple-plugin.html&quot; rel=&quot;nofollow&quot;&gt;官方示例&lt;/a&gt;&lt;/p&gt;
&lt;h1 dir=&quot;auto&quot;&gt;总结&lt;/h1&gt;
&lt;p dir=&quot;auto&quot;&gt;CKEditor5 本身拥有良好且完善的规范， 在这套规范的基础上我们能很快的上手开发和维护插件， 由于其良好的通用性，我们可以开发更多有趣的或者实用的插件共享到开源社区。&lt;/p&gt;</content>
</entry>
<entry>
<title>Google IO for web platform</title>
<link href="https://tech.jinshuju.net/posts/6/"/>
<id>https://tech.jinshuju.net/posts/6/</id>
<published>2022-05-15T12:43:29Z</published>
<updated>2022-05-16T03:27:48Z</updated>
<author><name>silverWolf818</name></author>
<category term="frontend"/>
<category term="platform"/>
<category term="browser"/>
<content type="html">&lt;h1 dir=&quot;auto&quot;&gt;一、 What's new for the web platform&lt;/h1&gt;
&lt;p dir=&quot;auto&quot;&gt;直接上视频地址 &lt;a href=&quot;https://www.youtube.com/watch?v=5b4YcLB4DVI&amp;amp;t=1807s&quot; rel=&quot;nofollow&quot;&gt;What's new for the web platform&lt;/a&gt;，然后我简单的根据视频的内容总结了一下 HTML 、CSS 和 JavaScript 的新特性。&lt;/p&gt;
&lt;h1 dir=&quot;auto&quot;&gt;二、HTML 和 CSS 新特性&lt;/h1&gt;
&lt;h2 dir=&quot;auto&quot;&gt;accent-color&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;这个属性可以修改例如原生的单选、多选、范围等组件的颜色。&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/accent-color&quot; rel=&quot;nofollow&quot;&gt;accent-color MDN&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/5e2d82245bbc0e875c8e4f46b14d4651ab9241232b44946ae9631cd13a6aa0a7/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323531363133323032302e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/5e2d82245bbc0e875c8e4f46b14d4651ab9241232b44946ae9631cd13a6aa0a7/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323531363133323032302e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1652516132020.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;接下来我们来实际体验一下，代码如下：&lt;a href=&quot;https://stackblitz.com/edit/react-cygg2k?file=src%2FApp.js,src%2Fstyle.css&quot; rel=&quot;nofollow&quot;&gt;在线预览&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;useState&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'react'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'./style.css'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setColor&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'#50E3C2'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;left&quot;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;radio&quot;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;accentColor&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;radio&quot;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;checked&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;accentColor&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;checkbox&quot;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;accentColor&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;checkbox&quot;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;checked&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;accentColor&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt;
            &lt;span class=&quot;pl-c1&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;range&quot;&lt;/span&gt;
            &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;range&quot;&lt;/span&gt;
            &lt;span class=&quot;pl-c1&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;accentColor&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;right&quot;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;color&quot;&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;color&quot;&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;onChange&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setColor&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;我们可以通过颜色选择器选择任意的颜色来修改原生组件的颜色了。如下图所示：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/b9058b7977c79a9a2e8235c638eded12855cb8dd24fa470a5a7a91c2121adfc6/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323531393438303232392e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/b9058b7977c79a9a2e8235c638eded12855cb8dd24fa470a5a7a91c2121adfc6/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323531393438303232392e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1652519480229.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;dialog&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;新版的 &lt;code class=&quot;notranslate&quot;&gt;dialog&lt;/code&gt; 内置了一些可访问性和可用性的功能。&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/dialog&quot; rel=&quot;nofollow&quot;&gt;dialog MDN&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/8e972a81ddd638d5fdfd2f1cc93cc0fe026a2fdd87ae6360cbbfc8b7d47c9ecc/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323539323638303235392e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/8e972a81ddd638d5fdfd2f1cc93cc0fe026a2fdd87ae6360cbbfc8b7d47c9ecc/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323539323638303235392e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1652592680259.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;我们来实际体验一下，代码如下：&lt;a href=&quot;https://stackblitz.com/edit/web-platform-y4rtpw?file=index.html&quot; rel=&quot;nofollow&quot;&gt;在线预览&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-text-html-basic&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;meta&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;charset&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;UTF-8&lt;/span&gt;&quot; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;dialog&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;id&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;dialog&lt;/span&gt;&quot;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;method&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;dialog&lt;/span&gt;&quot;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;label&lt;/span&gt;
            &lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;name:
            &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;text&lt;/span&gt;&quot; &lt;span class=&quot;pl-c1&quot;&gt;name&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;name&lt;/span&gt;&quot; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;label&lt;/span&gt;
            &lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;email:
            &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;email&lt;/span&gt;&quot; &lt;span class=&quot;pl-c1&quot;&gt;name&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;name&lt;/span&gt;&quot; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;cancel&lt;/span&gt;&quot;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;Cancel&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;id&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;confirm&lt;/span&gt;&quot; &lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;default&lt;/span&gt;&quot;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;Confirm&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;dialog&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;id&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;open&lt;/span&gt;&quot;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;Open dialog&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'#open'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;dialog&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'#dialog'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'output'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'click'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-s1&quot;&gt;dialog&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;showModal&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;pl-s1&quot;&gt;dialog&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'close'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;onClose&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-s1&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;dialog&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;returnValue&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;' button clicked'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;新的 &lt;code class=&quot;notranslate&quot;&gt;dialog&lt;/code&gt; 可以使用 &lt;code class=&quot;notranslate&quot;&gt;Esc&lt;/code&gt; 来关闭弹窗，还可以通过 &lt;code class=&quot;notranslate&quot;&gt;dialog&lt;/code&gt; 的返回值来感觉我们点击了什么按钮。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/62d22029d7179ba9647f42bc3179a8fbec3979b29f5b82a8c6444cc09a819f93/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323539383133373732332e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/62d22029d7179ba9647f42bc3179a8fbec3979b29f5b82a8c6444cc09a819f93/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323539383133373732332e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1652598137723.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;datetime-local&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;datetime-local&lt;/code&gt; 这个 API 存在很久了，这一次进行了补全和完善。&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/input/datetime-local#%E4%BD%BF%E7%94%A8_datetime-local_%E8%BE%93%E5%85%A5%E6%8E%A7%E4%BB%B6&quot; rel=&quot;nofollow&quot;&gt;datetime-local MDN&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/b85f146fe98f4a67e517bfdb762cbed7596be49c22467311b4203431ec2df556/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323539383734383433342e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/b85f146fe98f4a67e517bfdb762cbed7596be49c22467311b4203431ec2df556/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323539383734383433342e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1652598748434.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;我们来实际体验一下，代码如下：&lt;a href=&quot;https://stackblitz.com/edit/web-platform-msd7eg?file=index.html&quot; rel=&quot;nofollow&quot;&gt;在线预览&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;party&quot;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;输入日期和时间：&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;party&quot;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;datetime-local&quot;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;partydate&quot;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;我们可以直接输入或者通过点击呼出弹窗来修改日期。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/a069d74b40fd7e6d17f22fdcd580f8eaba5ddc049359e3bcae8880d502a00504/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323539393235383631382e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/a069d74b40fd7e6d17f22fdcd580f8eaba5ddc049359e3bcae8880d502a00504/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323539393235383631382e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1652599258618.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;除了这些基本功能我们还可以添加最大和最小值等功能，由于篇幅原因这里挖一个坑，以后会有一篇来介绍这个 API。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;image lazy loading&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;记得在我刚入行那时还在使用 &lt;code class=&quot;notranslate&quot;&gt;jquery image loading&lt;/code&gt;，现在已经得到浏览器的支持。&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/img&quot; rel=&quot;nofollow&quot;&gt;iamge lazy loading MDN&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/12ddb1a4c61868d143baf2755a54cccc6d509b6d305d8fa5b205f76852e11120/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323630323633393630352e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/12ddb1a4c61868d143baf2755a54cccc6d509b6d305d8fa5b205f76852e11120/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323630323633393630352e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1652602639605.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;那就来看看浏览器的体验如何，代码如下：&lt;a href=&quot;https://stackblitz.com/edit/web-platform-tr6thg?file=index.html&quot; rel=&quot;nofollow&quot;&gt;在线预览&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-text-html-basic&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;meta&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;charset&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;UTF-8&lt;/span&gt;&quot; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;img&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;src&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;https://picsum.photos/id/1/300/800&lt;/span&gt;&quot;
        &lt;span class=&quot;pl-c1&quot;&gt;alt&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;pic&lt;/span&gt;&quot;
        &lt;span class=&quot;pl-c1&quot;&gt;loading&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;lazy&lt;/span&gt;&quot;
        &lt;span class=&quot;pl-c1&quot;&gt;width&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;300&lt;/span&gt;&quot;
        &lt;span class=&quot;pl-c1&quot;&gt;height&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;800&lt;/span&gt;&quot;
      &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
   ...............
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;img&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;src&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;https://picsum.photos/id/20/300/800&lt;/span&gt;&quot;
        &lt;span class=&quot;pl-c1&quot;&gt;alt&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;pic&lt;/span&gt;&quot;
        &lt;span class=&quot;pl-c1&quot;&gt;loading&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;lazy&lt;/span&gt;&quot;
        &lt;span class=&quot;pl-c1&quot;&gt;width&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;300&lt;/span&gt;&quot;
        &lt;span class=&quot;pl-c1&quot;&gt;height&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;800&lt;/span&gt;&quot;
      &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;这里我加载了 20 张图片，但是 chrome 开始只会加载 2 张图片，随着我们滚动的变化，图片就会继续加载。如图：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/056b83856021b3b64d065e8b3884b11c15ae6d65be0109dae770921dbe383f3e/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323630343135383334312e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/056b83856021b3b64d065e8b3884b11c15ae6d65be0109dae770921dbe383f3e/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323630343135383334312e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1652604158341.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这里也只是简单介绍一下，后面会专门开一个坑来详细介绍。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;aspect-ratio&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;如果是经常开发移动网站的同学应该多少会接触这个属性，&lt;code class=&quot;notranslate&quot;&gt;aspect-ratio&lt;/code&gt; 属性可以设置容器的横纵比。&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/CSS/aspect-ratio&quot; rel=&quot;nofollow&quot;&gt;aspect-ratio MDN&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/3525f0f3f922f9c512785491758744dcfeadf919216c34bf178ec37a80e62c1e/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323630353131323331382e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/3525f0f3f922f9c512785491758744dcfeadf919216c34bf178ec37a80e62c1e/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323630353131323331382e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1652605112318.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;实际应用一下这个属性，代码如下：&lt;a href=&quot;https://stackblitz.com/edit/web-platform-75xmwo?file=index.html&quot; rel=&quot;nofollow&quot;&gt;在线预览&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-text-html-basic&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;meta&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;charset&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;UTF-8&lt;/span&gt;&quot; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
      .&lt;span class=&quot;pl-c1&quot;&gt;bg&lt;/span&gt; {
        &lt;span class=&quot;pl-c1&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;20&lt;span class=&quot;pl-smi&quot;&gt;px&lt;/span&gt;&lt;/span&gt;;
        &lt;span class=&quot;pl-c1&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pl-pds&quot;&gt;&lt;span class=&quot;pl-kos&quot;&gt;#&lt;/span&gt;fff&lt;/span&gt;;
        &lt;span class=&quot;pl-c1&quot;&gt;aspect-ratio&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;9&lt;/span&gt;;
        &lt;span class=&quot;pl-c1&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;:&lt;/span&gt; red;
      }
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;class&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;bg&lt;/span&gt;&quot;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;div width aspect-ratio: 16 / 9&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;使用 &lt;code class=&quot;notranslate&quot;&gt;aspect-ratio&lt;/code&gt; 属性就能创建一个纵横比的容器，在移动端有背景自适应的项目很实用，如图所示：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/663bc0cb7771655e2a5c4501f276a9bb9e052038e6d361c22f2489ae0a138a26/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323631343236313539382e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/663bc0cb7771655e2a5c4501f276a9bb9e052038e6d361c22f2489ae0a138a26/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323631343236313539382e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1652614261598.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 dir=&quot;auto&quot;&gt;三、JavaScript 新特性&lt;/h1&gt;
&lt;h2 dir=&quot;auto&quot;&gt;Structured cloning&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;这个 API 是给我留下印象最深刻的 API - 深拷贝 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/structuredClone&quot; rel=&quot;nofollow&quot;&gt;structuredClone MDN&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/f760eeb41fe2221d6f4b301333910b53413f9ef449a9a8b0bbfe83297941c4b4/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323631343438323136342e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/f760eeb41fe2221d6f4b301333910b53413f9ef449a9a8b0bbfe83297941c4b4/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323631343438323136342e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1652614482164.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;直接上手体验一下，代码如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;original&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;'jsj'&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;clone&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;structuredClone&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;original&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-smi&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;clone&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;original&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;pl-c&quot;&gt;// false&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;更多详细内容可以查看官方文档，这里不做过多介绍。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;createImageBitmap&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;看了这次大会才知道还有这么一个 API（个人水平有待提高 😭），如果是经常处理图片的同学应该不会陌生，他会生成一个 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/ImageBitmap&quot; rel=&quot;nofollow&quot;&gt;ImageBitmap&lt;/a&gt; 格式的数据。&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/createImageBitmap&quot; rel=&quot;nofollow&quot;&gt;createImageBitmap&lt;/a&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/089413bc0000e416ff9db2b6e55cb2610f6cbc6c955bffa3c9f42cdbe7960b42/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323631363139343530392e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/089413bc0000e416ff9db2b6e55cb2610f6cbc6c955bffa3c9f42cdbe7960b42/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313635323631363139343530392e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1652616194509.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这个 API 具体能干嘛呢，以前我们预览图片会使用 &lt;code class=&quot;notranslate&quot;&gt;URL.createObjectURL&lt;/code&gt;，现在也可以使用 &lt;code class=&quot;notranslate&quot;&gt;createImageBitmap&lt;/code&gt; 来实现。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-text-html-basic&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;!DOCTYPE html&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;lang&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;en&lt;/span&gt;&quot;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;meta&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;charset&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;UTF-8&lt;/span&gt;&quot;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;图片本地预览示例&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;file&lt;/span&gt;&quot; &lt;span class=&quot;pl-c1&quot;&gt;accept&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;image/*&lt;/span&gt;&quot; &lt;span class=&quot;pl-c1&quot;&gt;onchange&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;loadFile(event)&lt;/span&gt;&quot;&lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;canvas&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;id&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;image&lt;/span&gt;&quot;&lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;loadFile&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;canvas&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'#pic'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;canvas&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'2d'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;blobToImage&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;createImageBitmap&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;drawImage&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;blobToImage&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;相比使用 &lt;code class=&quot;notranslate&quot;&gt;URL.createObjectURL&lt;/code&gt; 会方便许多。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-text-html-basic&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;!DOCTYPE html&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;lang&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;en&lt;/span&gt;&quot;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;meta&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;charset&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;UTF-8&lt;/span&gt;&quot;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;图片本地预览示例&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;file&lt;/span&gt;&quot; &lt;span class=&quot;pl-c1&quot;&gt;accept&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;image/*&lt;/span&gt;&quot; &lt;span class=&quot;pl-c1&quot;&gt;onchange&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;loadFile(event)&lt;/span&gt;&quot;&lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;id&lt;/span&gt;=&quot;&lt;span class=&quot;pl-s&quot;&gt;preview&lt;/span&gt;&quot;&lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;loadFile&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'#preview'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;createObjectURL&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;pl-s1&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;url&lt;/span&gt;
        &lt;span class=&quot;pl-s1&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;onload&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;pl-c1&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;revokeObjectURL&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-ent&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;这里我把 2 种 API 的实现方法都放在这里。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;at&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;数组新增了一个 &lt;code class=&quot;notranslate&quot;&gt;at&lt;/code&gt; 方法，接收一个整数值并返回该索引的项目，允许正数和负数。&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/at&quot; rel=&quot;nofollow&quot;&gt;Array.prototype.at()&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;现在就可以很方便的返回最后一项，代码如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;cart&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'apple'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'banana'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'pear'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-s1&quot;&gt;cart&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;pl-c&quot;&gt;// const last = cart[cart.length - 1]&lt;/span&gt;
&lt;span class=&quot;pl-c&quot;&gt;// const last = cart.slice(-1)[0]&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;相比数组和 &lt;code class=&quot;notranslate&quot;&gt;slice&lt;/code&gt; 方法更加快捷方便。&lt;/p&gt;
&lt;h1 dir=&quot;auto&quot;&gt;四、其他&lt;/h1&gt;
&lt;p dir=&quot;auto&quot;&gt;以上只是简单的介绍一个 HMTL、CSS 和 Javascript 的一些新的特性，还有其他新的特性和功能由于篇幅的限制这里就不展开说明，简单列举一些&lt;del&gt;挖个坑以后填&lt;/del&gt; 😄&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/bfcache/&quot; rel=&quot;nofollow&quot;&gt;bfcache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/priority-hints/&quot; rel=&quot;nofollow&quot;&gt;priority-hints&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/size-adjust&quot; rel=&quot;nofollow&quot;&gt;size-adjust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Authentication_API&quot; rel=&quot;nofollow&quot;&gt;web Auth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/virtualkeyboard/&quot; rel=&quot;nofollow&quot;&gt;Virtual Keyboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries&quot; rel=&quot;nofollow&quot;&gt;Container Queries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/CSS/:has&quot; rel=&quot;nofollow&quot;&gt;has&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;最后视频地址 - &lt;a href=&quot;https://www.youtube.com/watch?v=5b4YcLB4DVI&amp;amp;t=1807s&quot; rel=&quot;nofollow&quot;&gt;What's new for the web platform&lt;/a&gt;&lt;/p&gt;</content>
</entry>
<entry>
<title>学习 React-hook-form</title>
<link href="https://tech.jinshuju.net/posts/5/"/>
<id>https://tech.jinshuju.net/posts/5/</id>
<published>2021-12-05T14:23:23Z</published>
<updated>2021-12-08T06:30:59Z</updated>
<author><name>silverWolf818</name></author>
<category term="frontend"/>
<category term="React"/>
<content type="html">&lt;h1 dir=&quot;auto&quot;&gt;一、React 中的表单&lt;/h1&gt;
&lt;p dir=&quot;auto&quot;&gt;首选我们来看 React 官方如何实践表单处理。直接打开&lt;a href=&quot;https://zh-hans.reactjs.org/docs/forms.html&quot; rel=&quot;nofollow&quot;&gt;官方文档&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;官方给出了两种不同的表单方案，基于受控组件以及基于非受控组件的表单实现，当然前者会比较常见一些。所有的第三方表单都可以认为是这两种方案的延伸及封装。例如：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://redux-form.com/8.3.0/&quot; rel=&quot;nofollow&quot;&gt;redux-form&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://formik.org/&quot; rel=&quot;nofollow&quot;&gt;formik&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://final-form.org/react&quot; rel=&quot;nofollow&quot;&gt;final-form&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react-hook-form.com/&quot; rel=&quot;nofollow&quot;&gt;react-hook-form&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 dir=&quot;auto&quot;&gt;1. 受控组件&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;在 HTML 中，表单元素（如 &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;input&amp;gt;&lt;/code&gt;、 &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt; 和 &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;select&amp;gt;&lt;/code&gt;）通常自己维护 state，并根据用户输入进行更新。而在 React 中，可变状态（mutable state）通常保存在组件的 state 属性中，并且只能通过使用 &lt;code class=&quot;notranslate&quot;&gt;setState()&lt;/code&gt; 来更新。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;我们可以把两者结合起来，使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;简单来说就是指由父组件完全控制该组件的状态及回调函数，子组件的状态变更需要通过回调函数通知到父组件，由父组件完成状态变更后再将新值传回子组件。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;表现在代码上就是形如之类的表单组件同时接收 &lt;code class=&quot;notranslate&quot;&gt;value&lt;/code&gt; 以及 &lt;code class=&quot;notranslate&quot;&gt;onChange&lt;/code&gt; 这两个 &lt;code class=&quot;notranslate&quot;&gt;props&lt;/code&gt; 来实现受控。来看一个&lt;a href=&quot;https://zh-hans.reactjs.org/docs/forms.html&quot; rel=&quot;nofollow&quot;&gt;官方的实例&lt;/a&gt;：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;NameForm&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-en&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-smi&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;handleChange&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;handleChange&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;handleSubmit&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;handleSubmit&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;pl-en&quot;&gt;handleChange&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;pl-en&quot;&gt;handleSubmit&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'提交的名字: '&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;pl-en&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onSubmit&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;handleSubmit&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
          名字:
          &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onChange&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;handleChange&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;submit&quot;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;提交&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 dir=&quot;auto&quot;&gt;2. 非受控组件&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;刚说到受控组件所有的状态都由外界接管，非受控组件则恰恰相反，它将状态存储在自身内部，我们可以借用 React 中的 &lt;code class=&quot;notranslate&quot;&gt;ref&lt;/code&gt; 来访问它。同样还是来看一个&lt;a href=&quot;https://zh-hans.reactjs.org/docs/uncontrolled-components.html&quot; rel=&quot;nofollow&quot;&gt;官方的实例&lt;/a&gt;：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;NameForm&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-en&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-smi&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;handleSubmit&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;handleSubmit&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;createRef&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;pl-en&quot;&gt;handleSubmit&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'A name was submitted: '&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;pl-en&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onSubmit&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;handleSubmit&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
          Name:
          &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;submit&quot;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;Submit&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 dir=&quot;auto&quot;&gt;3. 如何选择&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;关于受控 vs 非受控的选择这个问题 🤔 ，我们就交给 google 帮助我们回答 &lt;code class=&quot;notranslate&quot;&gt;controlled vs uncontrolled in react&lt;/code&gt; 😜&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/42522515/what-are-react-controlled-components-and-uncontrolled-components&quot; rel=&quot;nofollow&quot;&gt;what-are-react-controlled-components-and-uncontrolled-components&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://goshacmd.com/controlled-vs-uncontrolled-inputs-react/#conclusion&quot; rel=&quot;nofollow&quot;&gt;Controlled and uncontrolled form inputs in React don't have to be complicated&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://itnext.io/controlled-vs-uncontrolled-components-in-react-5cd13b2075f9&quot; rel=&quot;nofollow&quot;&gt;Controlled vs Uncontrolled Components in React&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;查阅了许多文档，大部分文档认为应该优先考虑受控模式，主要举例说明受控之于非受控更灵活，更符合 react 单向数据流。这里还有一张对比图：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/e8bcd67e839e0db274e0b30c0cf3cc5fdb11929b0790d3b779b0d55141e175ef/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313633383630383631333637342e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/e8bcd67e839e0db274e0b30c0cf3cc5fdb11929b0790d3b779b0d55141e175ef/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313633383630383631333637342e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1638608613674.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;图中列举的一些非受控组件无法覆盖的场景，实际上 &lt;code class=&quot;notranslate&quot;&gt;ref&lt;/code&gt; 配合组件 &lt;code class=&quot;notranslate&quot;&gt;onChange&lt;/code&gt; 是可以做到的，例如字段的实时校验，我们完全可以在字段上挂上监听函数，在其值发生改变的时候进行字段校验，然后通过 &lt;code class=&quot;notranslate&quot;&gt;ref&lt;/code&gt; 控制组件的内部状态。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;说了这么多内容，其实问题的关键在于 React 理念，也就是我们常说的单向数据流 &lt;code class=&quot;notranslate&quot;&gt;ViewModel&lt;/code&gt; 🧐 。所以理所应当我们开发的程序也应该是如此。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/349ad6aa72b26b2d3f008d5f3bea7d442991795946ee954d66426471efe2899b/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313633383631333238323535372e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/349ad6aa72b26b2d3f008d5f3bea7d442991795946ee954d66426471efe2899b/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313633383631333238323535372e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1638613282557.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;受控和非受控是站在组件状态(值)的存储位置来看的，本质上受控与非受控的表达能力是相同的，从某种层面上看可以互相实现。&lt;/p&gt;
&lt;h1 dir=&quot;auto&quot;&gt;二、React-hook-form&lt;/h1&gt;
&lt;p dir=&quot;auto&quot;&gt;React-hook-form 是一个基于非受控组件实现的表单库。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;非受控表单就不是使用 &lt;code class=&quot;notranslate&quot;&gt;state&lt;/code&gt; 单向数据流来控制表单，它是通过 &lt;code class=&quot;notranslate&quot;&gt;ref&lt;/code&gt; 来直接拿到表单组件，从而可以直接拿到表单的值，不需要对表单的值进行状态维护，这就使得&lt;strong&gt;非受控表单可以减少很多不必要的渲染&lt;/strong&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;非受控表单也存在着它的问题，在动态校验、动态修改（联动）方面不是很方便，于是诞生了一个以非受控思想为基础的表单库 &lt;a href=&quot;https://react-hook-form.com/&quot; rel=&quot;nofollow&quot;&gt;react-hook-form&lt;/a&gt;，它可以帮助我们解决这些问题。还有一点好处就是基于非受控的组件，完全拥抱原生 HTML 标准。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;使用 &lt;code class=&quot;notranslate&quot;&gt;React&lt;/code&gt; 和 &lt;code class=&quot;notranslate&quot;&gt;React-hook-form&lt;/code&gt; 的&lt;a href=&quot;https://codesandbox.io/s/react-hook-form-get-started-forked-pw5pn&quot; rel=&quot;nofollow&quot;&gt;简单示例&lt;/a&gt;：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;react&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;useForm&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;react-hook-form&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; register&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; handleSubmit&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; watch&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;formState&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; errors &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useForm&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;onSubmit&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-smi&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;example&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;pl-c&quot;&gt;// watch input value by passing the name of it&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c&quot;&gt;/* &quot;handleSubmit&quot; will validate your inputs before invoking &quot;onSubmit&quot; */&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onSubmit&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;handleSubmit&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;onSubmit&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-c&quot;&gt;/* register your input into the hook by invoking the &quot;register&quot; function */&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;defaultValue&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;test&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;pl-en&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;example&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      
      &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-c&quot;&gt;/* include validation with required or other standard HTML validation rules */&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;pl-en&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;exampleRequired&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;required&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-c&quot;&gt;/* errors will return when field validation fails  */&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;exampleRequired&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;This field is required&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
      
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;submit&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 dir=&quot;auto&quot;&gt;1. 核心原理&lt;/h3&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;表单初始化&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;我们看到 &lt;code class=&quot;notranslate&quot;&gt;react-hook-form&lt;/code&gt; 在使用时必须先调用 &lt;code class=&quot;notranslate&quot;&gt;useForm&lt;/code&gt; 方法，该方法返回了一系列表单相关的 API。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;useForm&lt;/code&gt; 方法内部都干了什么 🤔 ？&lt;/p&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;定义表单状态，例如 &lt;code class=&quot;notranslate&quot;&gt;isDirty&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;isValidating&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;dirtyFields&lt;/code&gt; 等。&lt;a href=&quot;https://github.com/react-hook-form/react-hook-form/blob/master/src/useForm.ts#L25&quot;&gt;源码位置&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;formState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;updateFormState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;FormState&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;isDirty&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;isValidating&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;dirtyFields&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;FieldNamesMarkedBoolean&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;isSubmitted&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;submitCount&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;touchedFields&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;FieldNamesMarkedBoolean&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;isSubmitting&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;isSubmitSuccessful&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;isValid&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;errors&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;FieldErrors&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;2&quot; dir=&quot;auto&quot;&gt;
&lt;li&gt;创建表单控制器属性及方法。&lt;a href=&quot;https://github.com/react-hook-form/react-hook-form/blob/master/src/useForm.ts#L38&quot;&gt;源码位置&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;_formControl&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-s1&quot;&gt;_formControl&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;_options&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-s1&quot;&gt;_formControl&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;current&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    ...&lt;span class=&quot;pl-en&quot;&gt;createFormControl&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    formState&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;这里的 &lt;code class=&quot;notranslate&quot;&gt;createFormControl&lt;/code&gt; 方法是 &lt;code class=&quot;notranslate&quot;&gt;react-hook-form&lt;/code&gt; 的核心，表单整体的状态以及表单提供对外的 API，如&lt;code class=&quot;notranslate&quot;&gt;handleSubmit&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;setValue&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;getValues&lt;/code&gt; 校验等，以及字段的注册、订阅方法等等都会这里预先处理。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;createFormControl&lt;/code&gt; 方法定义的内如下，这里只是一部分。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这部分中有一个很重要的内容就是 &lt;code class=&quot;notranslate&quot;&gt;_subjects&lt;/code&gt; 这内部属性，它会创建一个发布订阅的实例，表单字段可以通过该实例进行字段间的通信，达到字段关联的目的。&lt;a href=&quot;https://github.com/react-hook-form/react-hook-form/blob/1f8bfc481d5704b4a46cf716e0e104f24ad71834/src/logic/createFormControl.ts#L101&quot;&gt;源码位置&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-s1&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_formState&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;FormState&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;isDirty&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;isValidating&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;dirtyFields&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;FieldNamesMarkedBoolean&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;isSubmitted&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;submitCount&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;touchedFields&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;FieldNamesMarkedBoolean&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;isSubmitting&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;isSubmitSuccessful&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;isValid&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;errors&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;FieldErrors&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_fields&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_defaultValues&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_options&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;defaultValues&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_formValues&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_options&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;shouldUnregister&lt;/span&gt;
  ? &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
  : &lt;span class=&quot;pl-en&quot;&gt;cloneObject&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;_defaultValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_stateFlags&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;action&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;mount&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;watch&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
let &lt;span class=&quot;pl-s1&quot;&gt;_names&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;Names&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;mount&lt;/span&gt;: &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;unMount&lt;/span&gt;: &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;array&lt;/span&gt;: &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;watch&lt;/span&gt;: &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Names&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
let &lt;span class=&quot;pl-s1&quot;&gt;delayErrorCallback&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;DelayCallback&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;timer&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-s1&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;validateFields&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;Record&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;InternalFieldName&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_proxyFormState&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;isDirty&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;dirtyFields&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;touchedFields&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;isValidating&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;isValid&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;errors&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_subjects&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;Subjects&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt; = &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-s1&quot;&gt;watch&lt;/span&gt;: &lt;span class=&quot;pl-en&quot;&gt;createSubject&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-s1&quot;&gt;array&lt;/span&gt;: &lt;span class=&quot;pl-en&quot;&gt;createSubject&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-s1&quot;&gt;state&lt;/span&gt;: &lt;span class=&quot;pl-en&quot;&gt;createSubject&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;createFormControl&lt;/code&gt; 方法返回的属性及其方法（&lt;code class=&quot;notranslate&quot;&gt;_&lt;/code&gt;标识的属性和方法属于 &lt;code class=&quot;notranslate&quot;&gt;react-hook-form&lt;/code&gt; 内部方法不对外暴露），就是 &lt;code class=&quot;notranslate&quot;&gt;useForm&lt;/code&gt; 对用户暴露的 API。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;control&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    register&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    unregister&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    _executeSchema&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    _getWatch&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    _getDirty&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    _updateValid&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    _removeUnmounted&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    _updateFieldArray&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    _getFieldArray&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    _subjects&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    _proxyFormState&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;_fields&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_fields&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;_fields&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;_fields&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;_formValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_formValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;_formValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;_formValues&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;_stateFlags&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_stateFlags&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;_stateFlags&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;_stateFlags&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;_defaultValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_defaultValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;_defaultValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;_defaultValues&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;_names&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_names&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;_names&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;_names&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;_formState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_formState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;_formState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;_formState&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;_options&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_options&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;_options&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;_options&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        ...&lt;span class=&quot;pl-s1&quot;&gt;_options&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
        ...&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  trigger&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  register&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  handleSubmit&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  watch&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  setValue&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  getValues&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  reset&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  resetField&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  clearErrors&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  unregister&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  setError&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  setFocus&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;3&quot; dir=&quot;auto&quot;&gt;
&lt;li&gt;观察表单整体的状态变化&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=&quot;auto&quot;&gt;接着我们继续回到 &lt;code class=&quot;notranslate&quot;&gt;useForm&lt;/code&gt; 方法，&lt;code class=&quot;notranslate&quot;&gt;react-hook-form&lt;/code&gt; 还会观察表单的变化，来更新表单的状态（例如：校验，是否修改等）。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-en&quot;&gt;useSubscribe&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;subject&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;_subjects&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-en&quot;&gt;callback&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;shouldRenderFormState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;_proxyFormState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;_formState&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        ...&lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;_formState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
        ...&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;pl-en&quot;&gt;updateFormState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; ...&lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;_formState&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;注册字段&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;注册字段目前 &lt;code class=&quot;notranslate&quot;&gt;react-hook-form&lt;/code&gt; 提供 3 中 API。&lt;/p&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;register&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;register&lt;/code&gt; 方法提供对外非受控控件 &lt;code class=&quot;notranslate&quot;&gt;ref&lt;/code&gt; 属性及其更改方法。&lt;a href=&quot;https://github.com/react-hook-form/react-hook-form/blob/1f8bfc481d5704b4a46cf716e0e104f24ad71834/src/logic/createFormControl.ts#L868&quot;&gt;源码位置&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;register&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;UseFormRegister&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt; = (name, options = &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;) =&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;_fields&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;pl-c&quot;&gt;//...&lt;/span&gt;

    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      name&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
      onChange&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;onBlur&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;onChange&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;ref&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;ref&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;HTMLInputElement&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        field &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;_fields&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

          &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;_f&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;pl-s1&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;_f&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;mount&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

          &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;_options&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;shouldUnregister&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;shouldUnregister&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class=&quot;pl-c1&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;isNameInFieldArray&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;_names&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_stateFlags&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class=&quot;pl-s1&quot;&gt;_names&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;unMount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;2&quot; dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;Controller&lt;/code&gt; 和 &lt;code class=&quot;notranslate&quot;&gt;useController&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;Controller&lt;/code&gt; 是以 React 组件的形式进行注册，其核心使用的是 &lt;code class=&quot;notranslate&quot;&gt;useController&lt;/code&gt;。&lt;a href=&quot;https://github.com/react-hook-form/react-hook-form/blob/1f8bfc481d/src/controller.tsx#L9&quot;&gt;源码位置&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Controller&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;
  &lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;FieldValues&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;FieldValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;TName&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;FieldPath&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt; = FieldPath&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;,
&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;ControllerProps&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;TName&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;,
) =&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;useController&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;TName&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;(props));

export &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Controller&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;这里重点介绍 &lt;code class=&quot;notranslate&quot;&gt;useController&lt;/code&gt; 这个钩子方法。** 在实际项目中会更倾向采用 &lt;code class=&quot;notranslate&quot;&gt;useController&lt;/code&gt; 方式注册字段 **&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;useController&lt;/code&gt; 内部实现很有意思 🤪 。&lt;/p&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;字段值得获取。&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;useController&lt;/code&gt; 直接使用订阅的方式获取字段的值。&lt;a href=&quot;https://github.com/react-hook-form/react-hook-form/blob/1f8bfc481d/src/useController.ts#L30&quot;&gt;源码位置&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useWatch&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  control&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  name&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;defaultValue&lt;/span&gt;: &lt;span class=&quot;pl-en&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;_formValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;_defaultValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;defaultValue&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;exact&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;isArrayField&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;UnpackNestedValue&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;FieldPathValue&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;TName&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;2&quot; dir=&quot;auto&quot;&gt;
&lt;li&gt;字段通过 &lt;code class=&quot;notranslate&quot;&gt;register&lt;/code&gt; 注册。&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;useController&lt;/code&gt; 内部还是使用 &lt;code class=&quot;notranslate&quot;&gt;register&lt;/code&gt; 来注册字段，这就是为什么 &lt;code class=&quot;notranslate&quot;&gt;createFormControl&lt;/code&gt; 会返回一个 &lt;code class=&quot;notranslate&quot;&gt;control&lt;/code&gt; 属性并且其中包含了 &lt;code class=&quot;notranslate&quot;&gt;register&lt;/code&gt; 方法。&lt;a href=&quot;https://github.com/react-hook-form/react-hook-form/blob/1f8bfc481d/src/useController.ts#L48&quot;&gt;源码位置&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;useController&lt;/code&gt; hook 是为了字段的分布式注册。而不局限于 &lt;code class=&quot;notranslate&quot;&gt;useForm&lt;/code&gt; 的 &lt;code class=&quot;notranslate&quot;&gt;register&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;registerProps&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    ...&lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    value&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;表单提交&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;react-hook-form&lt;/code&gt; 表单的提交相对简单，在内部通过 &lt;code class=&quot;notranslate&quot;&gt;_formValues&lt;/code&gt; 来收集分布式注册的字段的值，然后进行提交。&lt;a href=&quot;https://github.com/react-hook-form/react-hook-form/blob/1f8bfc481d/src/logic/createFormControl.ts#L960&quot;&gt;源码位置&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;handleSubmit&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;UseFormHandleSubmit&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt; =
(onValid, onInvalid) =&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  let &lt;span class=&quot;pl-s1&quot;&gt;fieldValues&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_options&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;shouldUnregister&lt;/span&gt;
    ? &lt;span class=&quot;pl-en&quot;&gt;cloneObject&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;_formValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
    : &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; ...&lt;span class=&quot;pl-s1&quot;&gt;_formValues&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-s1&quot;&gt;_subjects&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;isSubmitting&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-c&quot;&gt;// ....&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 dir=&quot;auto&quot;&gt;2. 表单交互&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;当我们进行表单交互 &lt;code class=&quot;notranslate&quot;&gt;react-hook-form&lt;/code&gt; 中又做了什么呢？ 🤔&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;createFormControl&lt;/code&gt; 中的 &lt;code class=&quot;notranslate&quot;&gt;onChange&lt;/code&gt; 方法就是来相应表单交互的变化。&lt;a href=&quot;https://github.com/react-hook-form/react-hook-form/blob/1f8bfc481d/src/logic/createFormControl.ts#L607&quot;&gt;源码位置&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;onChange&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;ChangeHandler&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;field&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;Field&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;_fields&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;isValid&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;fieldValue&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;
      ? &lt;span class=&quot;pl-en&quot;&gt;getFieldValue&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;_f&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
      : &lt;span class=&quot;pl-en&quot;&gt;getEventValue&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;pl-en&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;_formValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;fieldValue&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
	
    &lt;span class=&quot;pl-c&quot;&gt;//...&lt;/span&gt;
    
    &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;fieldState&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;updateTouchAndDirty&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;fieldValue&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;isBlurEvent&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;shouldRender&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;isEmptyObject&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;fieldState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;watched&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;pl-s1&quot;&gt;validateFields&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;validateFields&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; ? &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt; : &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;pl-s1&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;_f&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;deps&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;_f&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;deps&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;FieldPath&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;pl-en&quot;&gt;shouldRenderByError&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;isValid&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;fieldState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;这里首先会获取当前值变化的字段信息，然后还会判断该字段是否被 &lt;code class=&quot;notranslate&quot;&gt;watch&lt;/code&gt; ，还有对字段进行 &lt;code class=&quot;notranslate&quot;&gt;validateFields&lt;/code&gt; 操作。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这里总结一下 &lt;code class=&quot;notranslate&quot;&gt;react-hook-form&lt;/code&gt; 基本流程：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;表单初始化&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/131d3b02aa527805f348d02d385c5fe2051dc6f10a6c7480425f1524d1ab3e09/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313633383633323531343931352e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/131d3b02aa527805f348d02d385c5fe2051dc6f10a6c7480425f1524d1ab3e09/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313633383633323531343931352e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1638632514915.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;表单交互&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/8dfc99f295719f76db078861f716559ccb80524d1b4bb3fd5687048277d1ee45/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313633383633323937353739312e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/8dfc99f295719f76db078861f716559ccb80524d1b4bb3fd5687048277d1ee45/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313633383633323937353739312e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1638632975791.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;react-hook-form&lt;/code&gt; 都是基于字段级别的渲染：&lt;/p&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;
&lt;p dir=&quot;auto&quot;&gt;字段分布式注册，每一个字段的状态由组件自己负责，并不需要数据回流。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p dir=&quot;auto&quot;&gt;表单的内部状态(&lt;code class=&quot;notranslate&quot;&gt;isDirty&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;touched&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;isSubmitting&lt;/code&gt; 等)统一用过 Proxy 包装， 在初次渲染的时候利用 Proxy 记录用户对于各个状态的订阅情况，不订阅的话变化将被忽略，不引发重新渲染。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p dir=&quot;auto&quot;&gt;对错误进行浅层比较，例如上一轮渲染已经展示了错误信息，如果这一轮渲染错误信息不变的话，则不重新渲染.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p dir=&quot;auto&quot;&gt;虽然 &lt;code class=&quot;notranslate&quot;&gt;watch&lt;/code&gt; 默认会触发全局渲染，不过 &lt;code class=&quot;notranslate&quot;&gt;useWatch&lt;/code&gt; 可以做到不触发全局渲染的情况下通知某个字段的更新，本质上是发布订阅机制。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 dir=&quot;auto&quot;&gt;3. 动态校验以及联动&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;为了支持动态校验，&lt;code class=&quot;notranslate&quot;&gt;react-hook-form&lt;/code&gt; 在进行表单注册的时候还会将 &lt;code class=&quot;notranslate&quot;&gt;onChange&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;onBlur&lt;/code&gt; 等事件挂载到表单组件上，保证对与用户输入、修改行为的监听，从而可以对表单校验、表单值监听等进行触发。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;非受控表单除了动态校验的问题，还存在联动实现的问题。由于 &lt;code class=&quot;notranslate&quot;&gt;react-hook-form&lt;/code&gt; 不会将表单的值维护在 React 的 &lt;code class=&quot;notranslate&quot;&gt;state&lt;/code&gt; 中，用户输入不会触发其他组件的更新，因此 &lt;code class=&quot;notranslate&quot;&gt;react-hook-form&lt;/code&gt; 提供了 &lt;code class=&quot;notranslate&quot;&gt;watch&lt;/code&gt; 和性能更好的 &lt;code class=&quot;notranslate&quot;&gt;useWatch&lt;/code&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://react-hook-form.com/api/useform/watch&quot; rel=&quot;nofollow&quot;&gt;watch&lt;/a&gt; 官方示例：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;react&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;useForm&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;react-hook-form&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; register&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; watch&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;formState&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; errors &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; handleSubmit &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useForm&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;watchShowAge&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;showAge&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;pl-c&quot;&gt;// you can supply default value as second argument&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;watchAllFields&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;pl-c&quot;&gt;// when pass nothing as argument, you are watching everything&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;watchFields&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;showAge&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;pl-c&quot;&gt;// you can also target specific fields by their names&lt;/span&gt;

  &lt;span class=&quot;pl-c&quot;&gt;// Callback version of watch.  It's your responsibility to unsubscribe when done.&lt;/span&gt;
  &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;subscription&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; type &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;subscription&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;unsubscribe&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;onSubmit&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onSubmit&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;handleSubmit&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;onSubmit&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;checkbox&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;pl-en&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;showAge&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
        
        &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-c&quot;&gt;/* based on yes selection to display Age Input*/&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;watchShowAge&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;number&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;pl-en&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;age&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;min&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
        
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;submit&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://react-hook-form.com/api/usewatch&quot; rel=&quot;nofollow&quot;&gt;useWatch&lt;/a&gt; 官方示例：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;react&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;useForm&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;useWatch&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;react-hook-form&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;FirstNameWatched&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; control &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;firstName&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useWatch&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    control&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&quot;firstName&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c&quot;&gt;// without supply name will watch the entire form, or ['firstName', 'lastName'] to watch both&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;defaultValue&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&quot;default&quot;&lt;/span&gt; &lt;span class=&quot;pl-c&quot;&gt;// default value before the render&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;Watch: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;pl-c&quot;&gt;// only re-render at the component level, when firstName changes&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; register&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; control&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; handleSubmit &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useForm&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;onSubmit&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-smi&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onSubmit&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;handleSubmit&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;onSubmit&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;pl-en&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;firstName&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;pl-en&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;lastName&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;submit&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;FirstNameWatched&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;两者是存在新能差异的，&lt;code class=&quot;notranslate&quot;&gt;useWatch&lt;/code&gt; 可以认为是把更新移到了更局部的位置，所以性能上会更有优势。下图：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/2b35fc48d6d56298e41d78f906eea802ab73c0215534885db7b8973e81ce5ad3/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313633383633323435303730372e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/2b35fc48d6d56298e41d78f906eea802ab73c0215534885db7b8973e81ce5ad3/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313633383633323435303730372e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1638632450707.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 dir=&quot;auto&quot;&gt;三、动态数组字段&lt;/h1&gt;
&lt;p dir=&quot;auto&quot;&gt;在复杂的表单应用中，还需要动态增减数组字段。&lt;code class=&quot;notranslate&quot;&gt;react-hook-form&lt;/code&gt; 提供了一个 &lt;code class=&quot;notranslate&quot;&gt;useFieldArray&lt;/code&gt; 的API，来帮助我们实现。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;我们来看一个官方示例：&lt;a href=&quot;https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn&quot; rel=&quot;nofollow&quot;&gt;代码地址&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;react&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;useForm&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;useFieldArray&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;react-hook-form&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; register&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; control&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; handleSubmit&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; reset&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; trigger&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; setError &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useForm&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-c&quot;&gt;// defaultValues: {}; you can populate the fields by this attribute &lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; fields&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; append &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useFieldArray&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    control&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&quot;test&quot;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onSubmit&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;handleSubmit&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;pl-en&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;`test.&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-kos&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/span&gt;.firstName`&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Controller&lt;/span&gt;
              &lt;span class=&quot;pl-c1&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; field &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;pl-s1&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
              &lt;span class=&quot;pl-c1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;`test.&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-kos&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/span&gt;.lastName`&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
              &lt;span class=&quot;pl-c1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;button&quot;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;Delete&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;li&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;button&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;button&quot;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;firstName&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&quot;bill&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;lastName&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&quot;luo&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        append
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;submit&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;useFieldArray&lt;/code&gt; 使用也很简单，该返回一个 &lt;code class=&quot;notranslate&quot;&gt;fields&lt;/code&gt; 和若干操作数组的方法例如（&lt;code class=&quot;notranslate&quot;&gt;append&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;insert&lt;/code&gt;）。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;需要注意的是 &lt;code class=&quot;notranslate&quot;&gt;useFieldArray&lt;/code&gt; 返回的 &lt;code class=&quot;notranslate&quot;&gt;fields&lt;/code&gt; 是一个不受控制的字段这点很重要。这意味着它不会存储在全局的 &lt;code class=&quot;notranslate&quot;&gt;_formValues&lt;/code&gt; 中，所以在使用 &lt;code class=&quot;notranslate&quot;&gt;useFieldArray&lt;/code&gt; 遍历动态字段的时候，还需要我们自己对需要操作的数据进行一次注册操作。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;在 &lt;code class=&quot;notranslate&quot;&gt;useFieldArray&lt;/code&gt; 中注册动态字段：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Controller&lt;/span&gt;
	&lt;span class=&quot;pl-c1&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; field &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;pl-s1&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;pl-c1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;`test.&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-kos&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/span&gt;.lastName`&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;pl-c1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;但是这样就会有一个问题，动态注册的字段，数据变化并不会反应到 &lt;code class=&quot;notranslate&quot;&gt;fields&lt;/code&gt; 中。这是为什么呢？ 🤔&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;我们直接阅读源码：&lt;a href=&quot;https://github.com/react-hook-form/react-hook-form/blob/1f8bfc481d/src/useFieldArray.ts#L48&quot;&gt;源码位置&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;methods&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useFormContext&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  control &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  name&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  keyName &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'id'&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;TKeyName&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  shouldUnregister&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setFields&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;
  &lt;span class=&quot;pl-v&quot;&gt;Partial&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;FieldArrayWithId&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;TFieldArrayName&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;TKeyName&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;mapIds&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;_getFieldArray&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;keyName&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_fieldIds&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_name&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_actioned&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-s1&quot;&gt;_name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;current&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-s1&quot;&gt;_fieldIds&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;current&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;_names&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-en&quot;&gt;useSubscribe&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-en&quot;&gt;callback&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; values&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;fieldArrayName&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;fieldArrayName&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;current&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;fieldArrayName&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;setFields&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;mapIds&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;keyName&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;subject&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;_subjects&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;我们发现 &lt;code class=&quot;notranslate&quot;&gt;fields&lt;/code&gt; 是 &lt;code class=&quot;notranslate&quot;&gt;useFieldArray&lt;/code&gt; 自己内部维护的一个状态。同时 &lt;code class=&quot;notranslate&quot;&gt;useFieldArray&lt;/code&gt; 内部也订阅了一个 &lt;code class=&quot;notranslate&quot;&gt;control._subjects.array&lt;/code&gt;，可以在全局监听变化或修改。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;接着我们继续往下看，&lt;code class=&quot;notranslate&quot;&gt;append&lt;/code&gt; 方法，&lt;code class=&quot;notranslate&quot;&gt;append&lt;/code&gt; 方法会帮我们动态添加字段。并且我们发现它还会调用 &lt;code class=&quot;notranslate&quot;&gt;control._updateFieldArray&lt;/code&gt; 也就是会更新全局的表单数据。&lt;code class=&quot;notranslate&quot;&gt;prepend&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;remove&lt;/code&gt; 等 API 也是如此。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;append&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;:
      &lt;span class=&quot;pl-c1&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Partial&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;FieldArray&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;TFieldArrayName&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Partial&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;FieldArray&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;TFieldValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;TFieldArrayName&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;options&lt;/span&gt;?&lt;span class=&quot;pl-s1&quot;&gt;&lt;/span&gt;: &lt;span class=&quot;pl-v&quot;&gt;FieldArrayMethodProps&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;const&lt;/span&gt; appendValue &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;convertToArrayPayload&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;updatedFieldArrayValuesWithKey&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;appendAt&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;pl-en&quot;&gt;mapCurrentIds&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;_getFieldArray&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;_fieldIds&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;keyName&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;pl-en&quot;&gt;mapIds&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;appendValue&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;keyName&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;setFields&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;updatedFieldArrayValuesWithKey&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;_updateFieldArray&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;appendAt&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;argA&lt;/span&gt;: &lt;span class=&quot;pl-en&quot;&gt;fillEmptyArray&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;pl-en&quot;&gt;updateValues&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;updatedFieldArrayValuesWithKey&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;_names&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;focus&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;getFocusFieldName&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;updatedFieldArrayValuesWithKey&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;appendValue&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;这里我们可以得出结论就是，想要更新 &lt;code class=&quot;notranslate&quot;&gt;fields&lt;/code&gt; 就需要调用 &lt;code class=&quot;notranslate&quot;&gt;useFieldArray&lt;/code&gt; 提供的 API 方法或者通过全局 &lt;code class=&quot;notranslate&quot;&gt;setValue&lt;/code&gt; 方式修改，通过动态注册字段的方式无法修改 &lt;code class=&quot;notranslate&quot;&gt;fields&lt;/code&gt; 中的数据内容。至于为什么是这样的一种实现，官方的解释是 ** 提供更好的用户体验和表单性能。**&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;useFieldArray&lt;/code&gt; 的使用还有诸多使用细节，建议大家查看&lt;a href=&quot;https://react-hook-form.com/api/usefieldarray&quot; rel=&quot;nofollow&quot;&gt;官方文档&lt;/a&gt;，这里简单编写一个示例：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; register&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; control&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; handleSubmit&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; reset&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; watch &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useForm&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;defaultValues&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;test&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;firstName&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&quot;Bill&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;lastName&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&quot;Luo&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    fields&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    append&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    prepend&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    remove&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    swap&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    move&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    insert&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    replace
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useFieldArray&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    control&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&quot;test&quot;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;onSubmit&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;formValues&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useWatch&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; control &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-s1&quot;&gt;renderCount&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onSubmit&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;handleSubmit&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;onSubmit&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;Field Array &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;The following demo allow you to delete, append, prepend items&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;counter&quot;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;Render Count: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;renderCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
              &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;pl-en&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;`test.&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-kos&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/span&gt;.firstName`&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;

                &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Controller&lt;/span&gt;
                  &lt;span class=&quot;pl-c1&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; field &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;pl-s1&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
                  &lt;span class=&quot;pl-c1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;`test.&lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-kos&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/span&gt;.lastName`&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
                  &lt;span class=&quot;pl-c1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;control&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;button&quot;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
                  Delete
                &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
              &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;li&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;section&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;button&lt;/span&gt;
            &lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;button&quot;&lt;/span&gt;
            &lt;span class=&quot;pl-c1&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;pl-en&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;firstName&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&quot;appendBill&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;lastName&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&quot;appendLuo&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
            append
          &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;section&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;表单初始化数据 &lt;code class=&quot;notranslate&quot;&gt;useFieldArray&lt;/code&gt; 中的 &lt;code class=&quot;notranslate&quot;&gt;fields&lt;/code&gt; 和 &lt;code class=&quot;notranslate&quot;&gt;form&lt;/code&gt; 中的数据一致。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/564fa94c6f397008cd742e3643d055e2bf453758b0598d01b494a4fdcaac1cf4/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313633383731313830323631322e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/564fa94c6f397008cd742e3643d055e2bf453758b0598d01b494a4fdcaac1cf4/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313633383731313830323631322e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1638711802612.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;接着我们对数据进行操作就发现二者是有区别的，也就是我们之前所说的。通过动态注册字段的方式无法修改 &lt;code class=&quot;notranslate&quot;&gt;fields&lt;/code&gt; 中的数据内容。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://user-images.githubusercontent.com/7360502/145159776-fff04433-9479-46a0-9cca-b68c095ad001.png&quot;&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/7360502/145159776-fff04433-9479-46a0-9cca-b68c095ad001.png&quot; alt=&quot;image&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;接着我们通过 &lt;code class=&quot;notranslate&quot;&gt;useFieldArray&lt;/code&gt; 提供的 API 就可以修改 &lt;code class=&quot;notranslate&quot;&gt;fields&lt;/code&gt; 以及 &lt;code class=&quot;notranslate&quot;&gt;form&lt;/code&gt; 中的数据。但是会造成组件 Array 级别的渲染，性能下降。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/b5d3e8e67879cbf447386f255bdad579b05691dd9b9cd63a1d17b7a9f170336b/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313633383731323039313237322e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/b5d3e8e67879cbf447386f255bdad579b05691dd9b9cd63a1d17b7a9f170336b/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313633383731323039313237322e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1638712091272.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;使用建议：&lt;/p&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;如果数据需要用户操作，那么建议使用 &lt;code class=&quot;notranslate&quot;&gt;control&lt;/code&gt; 的方式注册字段，并且使用 &lt;code class=&quot;notranslate&quot;&gt;useWatch&lt;/code&gt; 来监听字段变化，而不是从 &lt;code class=&quot;notranslate&quot;&gt;fields&lt;/code&gt; 中获得。&lt;/li&gt;
&lt;li&gt;如果数据只是用作纯粹的展示使用，那么建议使用 &lt;code class=&quot;notranslate&quot;&gt;fields&lt;/code&gt; 中的数据即可。&lt;/li&gt;
&lt;li&gt;如果在 &lt;code class=&quot;notranslate&quot;&gt;useFieldArray&lt;/code&gt; 的 API 更新数据的时候遇到问题，建议使用 &lt;code class=&quot;notranslate&quot;&gt;setValue&lt;/code&gt; 来操作。（😕 需要具体分析）&lt;/li&gt;
&lt;li&gt;添加数据时需要确保数据结构的完整性，不然会造成数据初始化错乱。（例如：删除一条数据，然后追加一条数据）&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=&quot;auto&quot;&gt;到此我们就简单的了解了一下 &lt;code class=&quot;notranslate&quot;&gt;React-hook-form&lt;/code&gt;。&lt;/p&gt;</content>
</entry>
<entry>
<title>React 应用状态管理</title>
<link href="https://tech.jinshuju.net/posts/4/"/>
<id>https://tech.jinshuju.net/posts/4/</id>
<published>2021-09-18T02:34:07Z</published>
<updated>2021-09-23T01:24:02Z</updated>
<author><name>iwfan</name></author>
<category term="frontend"/>
<category term="JavaScript"/>
<category term="React"/>
<category term="translation"/>
<content type="html">&lt;p dir=&quot;auto&quot;&gt;🔗 原文链接：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://kentcdodds.com/blog/application-state-management-with-react&quot; rel=&quot;nofollow&quot;&gt;Application State Management with React&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;状态管理在任何应用中都是最难的部分。这也是为什么如此多的状态管理库层出不穷的原因。虽然状态管理本身是一个复杂的问题，但我认为让状态管理如此复杂的另一个原因就是我们经常 &lt;strong&gt;过度设计(over-engineer)&lt;/strong&gt; 我们的解决方案。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;在我使用React的过程中，有一个状态管理方案是我个人一直试图实现的，随着 React Hooks 的发布（以及 React Context 的大规模改进），这种状态管理方法已经被大幅简化。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;我们经常说 React 组件是构建应用的乐高积木，但有多少人会认为在积木中包含了状态管理呢？我个人解决状态管理问题的 &quot;秘密 &quot;是，&lt;strong&gt;考虑应用程序的状态在应用程序的树状结构中如何映射&lt;/strong&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;Redux 如此成功的原因之一是 react-redux 解决了 &lt;a href=&quot;https://kentcdodds.com/blog/prop-drilling&quot; rel=&quot;nofollow&quot;&gt;prop drilling&lt;/a&gt; 问题。你可以通过将组件传递到 &lt;code class=&quot;notranslate&quot;&gt;connect&lt;/code&gt; 函数中，从而在组件树中的不同位置共享数据。这一功能非常好，它对 reducer/action creators/等等的使用也很好，但我相信 Redux 的普遍性是因为它解决了开发者的 &lt;a href=&quot;https://kentcdodds.com/blog/prop-drilling&quot; rel=&quot;nofollow&quot;&gt;prop drilling&lt;/a&gt; 痛点。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;但这也是我很少使用 Redux 的原因：我不断的看到开发者将应用程序中的所有状态都砸到 Redux 中（不仅仅是全局状态，局部状态也是这样）。这导致了非常多的问题，其中最重要的一点是当你在维护任何状态的交互时，都涉及到 &lt;code class=&quot;notranslate&quot;&gt;reducers&lt;/code&gt;、 &lt;code class=&quot;notranslate&quot;&gt;action creatores/types&lt;/code&gt;、和 &lt;code class=&quot;notranslate&quot;&gt;dispatch&lt;/code&gt; 的调用。这最终导致你不得不打开许多文件，在你的脑海中追踪代码，以弄清楚正在发生什么，以及它对代码库的其他部分有什么影响。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;如果 Redux 管理的是 &lt;strong&gt;真正的全局状态&lt;/strong&gt;，这倒没有什么影响。但是对于简单状态的管理（如弹窗的打开/关闭状态 或者简单表单输入框的状态）就会变成一个大问题。更糟糕的是 Redux 的可扩展性不是很好，这就导致了如果你的应用变得越来越大，这个问题就会越来越难解决。你当然可以通过拆分 &lt;code class=&quot;notranslate&quot;&gt;reducers&lt;/code&gt; 管理应用的不同部分，从而降低维护状态的复杂度，但是间接执行所有的 &lt;code class=&quot;notranslate&quot;&gt;reducers&lt;/code&gt; 和 &lt;code class=&quot;notranslate&quot;&gt;action creators&lt;/code&gt; 的方案也不是最优解。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;即使不使用 Redux，将应用的所有状态放在单个对象中也可能导致其他问题。当一个 React 的 &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;Context.Provider&amp;gt;&lt;/code&gt; 中的值更新时，所有消费这个 Context 中数据的组件都会被更新并且都需要重新渲染，即使消费数据的组件是一个只关心一小部分数据的函数式组件。这可能会导致潜在的性能问题。（React-Redux v6 也试图使用此方法，直到他们意识这种方法不能兼容 Hooks 的运行逻辑，这迫使他们使用不同的方法在 v7 中来解决这些问题。）&lt;strong&gt;但我的观点是，如果你的状态在逻辑上更加分离，并且将状态置于更关心它的且离它更近的 React Tree Node 上，你就不会有这个问题&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;p dir=&quot;auto&quot;&gt;如果你正在用 React 来构建应用，那么在你的应用中本身就已经存在了一个状态管理库，你根本不需要执行 &lt;code class=&quot;notranslate&quot;&gt;npm install&lt;/code&gt; （或者 &lt;code class=&quot;notranslate&quot;&gt;yarn add&lt;/code&gt;）任何东西。你的用户不需要消耗额外的流量，它在NPM 上已经集成到所有的 React packages 中，并且 React team 已经为它提供了非常好的文档，它就是 React 本身。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;strong&gt;React 本身就是一个状态管理库&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;当你在构建一个 React 应用时，你其实是在用一堆组件构建一颗组件树，这个组件树的根是 &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;App /&amp;gt;&lt;/code&gt;，这棵树的最末端是一些原生的 &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;input&amp;gt;&lt;/code&gt; 、 &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;div&amp;gt;&lt;/code&gt; 和 &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;button&amp;gt;&lt;/code&gt; 等元素。这种UI的渲染方式并不是像原生 HTML 那样 — 将所有的元素都放在一个文件中来渲染UI，相反我们是用一个个独立的组件来管理组成UI的元素，这最终成为了构建UI的一个非常有效的方法。同理这种方式也可以用于状态管理，而且目前你很可能会这样做：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Counter&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Counter&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;注意我说的这些也可以用于 &lt;code class=&quot;notranslate&quot;&gt;class components&lt;/code&gt;, Hooks 只是让事情变得更容易了一些（特别是我们马上要介绍的 Context）&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Counter&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;count&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;count&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;count&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-en&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-smi&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;“ 好的 Kent, 在独立的组件中维护单个状态确实比较简单，但如果遇到跨组件状态共享时应该怎么处理呢？比如，如果我想这样做：”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;CountDisplay&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-c&quot;&gt;// where does `count` come from?&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;The current counter count is &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;CountDisplay&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Counter&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;“ &lt;code class=&quot;notranslate&quot;&gt;count&lt;/code&gt; 在 &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;Counter&amp;gt;&lt;/code&gt; 组件中，我需要一个状态管理工具能在 &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;CountDisplay&amp;gt;&lt;/code&gt; 中访问到 &lt;code class=&quot;notranslate&quot;&gt;count&lt;/code&gt; ，并且能在 &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;Counter&amp;gt;&lt;/code&gt; 中更新它! ”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;这个问题的答案在 React 刚发布时就已经存在了（或许更早？），并且我记得它一直在React的文档中：&lt;a href=&quot;https://reactjs.org/docs/lifting-state-up.html&quot; rel=&quot;nofollow&quot;&gt;状态提升&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;“状态提升”无疑是用来解答这个问题的最合理最正确的答案。你可以这样使用：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Counter&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;count&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; onIncrementClick&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;onIncrementClick&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;CountDisplay&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;count&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;The current counter count is &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;CountDisplay&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Counter&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onIncrementClick&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;我们刚刚将 &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;Counter&amp;gt;&lt;/code&gt; 管理 &lt;code class=&quot;notranslate&quot;&gt;count&lt;/code&gt; 的职责提升到了 &lt;code class=&quot;notranslate&quot;&gt;&amp;lt;App&amp;gt;&lt;/code&gt; 中，这真的很简单。而且我们还可以一直提升状态到应用程序的顶部。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;&quot;好的， Kent, 但是怎么处理 &lt;a href=&quot;https://kentcdodds.com/blog/prop-drilling&quot; rel=&quot;nofollow&quot;&gt;prop drilling&lt;/a&gt; 的问题呢？“&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;Great question.  第一步就是重新思考组件组织的方式，好好利用一下 &lt;a href=&quot;https://reactjs.org/docs/context.html#before-you-use-context&quot; rel=&quot;nofollow&quot;&gt;组件组合&lt;/a&gt;。看看这个例子：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setSomeState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'some state'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Header&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onStateChange&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;setSomeState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;LeftNav&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onStateChange&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;setSomeState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;MainContent&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onStateChange&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;setSomeState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;你可以这样使用组件组合的方式，重新组织组件树：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setSomeState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'some state'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Header&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;logo&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Logo&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Settings&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onStateChange&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;setSomeState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;LeftNav&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;SomeLink&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;SomeOtherLink&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Etc&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;LeftNav&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;MainContent&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;SomeSensibleComponent&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;AndSoOn&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;someState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;MainContent&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;如果你不是很清楚我在说什么的话，你可以看看 &lt;a href=&quot;https://twitter.com/mjackson&quot; rel=&quot;nofollow&quot;&gt;Michael Jackson&lt;/a&gt; 的 &lt;a href=&quot;https://www.youtube.com/watch?v=3XaXKiXtNjw&quot; rel=&quot;nofollow&quot;&gt;视频&lt;/a&gt; 可以帮助你理解我想表达的意思。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;但即使使用 &lt;code class=&quot;notranslate&quot;&gt;component composition&lt;/code&gt; 也不能完全解决 &lt;code class=&quot;notranslate&quot;&gt;props drilling&lt;/code&gt; 的问题。所以下一步就是使用 React 的 Context API。这实际上已经是一个 &quot;解决方案 &quot;了，但在很长一段时间里，这个解决方案是 &quot;非官方的&quot;。所以许多人都选择了 &lt;code class=&quot;notranslate&quot;&gt;react-redux&lt;/code&gt; ，因为它用我说的机制解决了这个问题，也不用担心 React 文档中的警告。但是现在 Context API 已经被官方支持，我们可以直接使用，没有任何问题。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;// src/count/count-context.js&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'react'&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;CountContext&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;createContext&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;useContext&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;CountContext&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;`useCount must be used within a CountProvider`&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;context&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;CountProvider&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;useMemo&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;CountContext&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;Provider&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;CountProvider&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;useCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-c&quot;&gt;// src/count/page.js&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'react'&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;CountProvider&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;useCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'./count-context'&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Counter&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;CountDisplay&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;The current counter count is &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;CountPage&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;CountProvider&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;CountDisplay&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Counter&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;CountProvider&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;该代码示例是精心策划的，我不建议你使用 Context 来解决此问题。请阅读 &lt;a href=&quot;https://kentcdodds.com/blog/prop-drilling&quot; rel=&quot;nofollow&quot;&gt;Prop Drilling&lt;/a&gt;， 以便更好地了解为什么 Prop Drilling 不一定是问题， 而且通常是可取的。不要把 Context 作为第一优先级的解决方案！&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这种方法的有趣之处在于我们可以把所有操作状态的公共逻辑抽取在 &lt;code class=&quot;notranslate&quot;&gt;useCount&lt;/code&gt; Hook 内：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;useContext&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;CountContext&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;`useCount must be used within a CountProvider`&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;context&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    count&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    setCount&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    increment&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;你也可以很容易地把 &lt;code class=&quot;notranslate&quot;&gt;useState&lt;/code&gt; 替换为 &lt;code class=&quot;notranslate&quot;&gt;useReducer&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;countReducer&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'INCREMENT'&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;count&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;default&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;`Unsupported action type: &lt;span class=&quot;pl-s1&quot;&gt;&lt;span class=&quot;pl-kos&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/span&gt;`&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;CountProvider&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;dispatch&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;useReducer&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;countReducer&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;count&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;useMemo&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;dispatch&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;CountContext&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;Provider&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;pl-s1&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;useContext&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;CountContext&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;`useCount must be used within a CountProvider`&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;dispatch&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;context&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;dispatch&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;type&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;'INCREMENT'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    state&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    dispatch&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    increment&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;这提供了巨大的灵活性，并将复杂程度降低了几个数量级。在这样做的时候，有几件重要的事情要记住:&lt;/p&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;在你的应用程序中，并非所有的东西都需要在一个单一的状态对象中，保持逻辑上的分离（用户设置不一定要和通知在同一个上下文中）。使用这种方法，你会有多个 Context。&lt;/li&gt;
&lt;li&gt;不是所有的上下文都需要在全局范围内访问! 尽可能地将状态保持在需要的地方。&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=&quot;auto&quot;&gt;更多关注在第二点上。你的应用程序树可能看起来像这样&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;ThemeProvider&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;AuthenticationProvider&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Router&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;/&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;About&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;/about&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;UserPage&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;/:userId&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;UserSettings&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;/settings&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Notifications&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;/notifications&quot;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Router&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;AuthenticationProvider&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;ThemeProvider&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Notifications&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;NotificationsProvider&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;NotificationsTab&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;NotificationsTypeList&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;NotificationsList&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;NotificationsProvider&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;UserPage&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;username&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;UserProvider&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;UserInfo&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;UserNav&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;UserActivity&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;UserProvider&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;UserSettings&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-c&quot;&gt;// this would be the associated hook for the AuthenticationProvider&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;user&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useAuthenticatedUser&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;请注意，每个页面都可以有自己的 Provider，每个 Provider 拥有它下面的组件所必需的数据。Code Splitting 对这个东西也是 &quot;有效的&quot;。数据如何进入每个 Provider，取决于这些 Provider 使用的Hook，以及你如何在应用程序中使用数据，但你知道从哪里开始查找数据流（在 Provider 中）。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;想了解更多更多关于这种方案的优点，请查阅 &lt;a href=&quot;https://kentcdodds.com/blog/state-colocation-will-make-your-react-app-faster&quot; rel=&quot;nofollow&quot;&gt;&quot;State Colocation will make your React app faster&quot;&lt;/a&gt; 和 &lt;a href=&quot;https://kentcdodds.com/blog/colocation&quot; rel=&quot;nofollow&quot;&gt;&quot;Colocation&quot;&lt;/a&gt;。如果想了解更多关于 context，阅读 &lt;a href=&quot;https://kentcdodds.com/blog/how-to-use-react-context-effectively&quot; rel=&quot;nofollow&quot;&gt;“How to use React Context effectively”&lt;/a&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;strong&gt;Server Cache 和 UI State&lt;/strong&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;最后再补充一件事，state 有各种类型，但每一种类型的 state 都可以归入两个大类中。&lt;/p&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;Server Cache - 状态实际上存储在服务端，我们将其存储在客户端中便于快速访问（像 用户信息）。&lt;/li&gt;
&lt;li&gt;UI State - 只用在 UI 层，用来控制应用的交互（如弹窗的 &lt;code class=&quot;notranslate&quot;&gt;isOpen&lt;/code&gt; 状态）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=&quot;auto&quot;&gt;当我们把这两者关联起来的时候，我们就犯了一个错误。 &lt;code class=&quot;notranslate&quot;&gt;Server Cache&lt;/code&gt; 在本质上与 &lt;code class=&quot;notranslate&quot;&gt;UI State&lt;/code&gt; 有着不同的问题，因此需要以不同的方式进行管理。如果你认可这个观点：你所拥有的实际上根本不是状态，而是状态的缓存，那么你就可以开始正确地思考它，从而正确地管理它。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;你肯定可以用你自己的 useState 或 useReducer，在恰当的位置用正确的 useContext 来管理这个问题。但请允许我帮助你提个醒，缓存是一个非常难的问题（有人说这是计算机科学中最难的问题之一），在这个问题上，站在巨人的肩膀上是明智的。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这就是为什么我使用并推荐 &lt;a href=&quot;https://github.com/tannerlinsley/react-query&quot;&gt;react-query&lt;/a&gt; 来处理这种状态。我知道，我告诉过你，你不需要一个状态管理库，但我并不认为 react-query 是一个状态管理库。我认为它是一个缓存。而且它是一个非常好的缓存。看看它吧， &lt;a href=&quot;https://twitter.com/tannerlinsley&quot; rel=&quot;nofollow&quot;&gt;Tanner Linsley&lt;/a&gt; 是个聪明人。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;strong&gt;性能如何 ？What about performance?&lt;/strong&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;当你遵循上述建议时，性能基本上不会是一个问题。特别是当你遵循&lt;a href=&quot;https://kentcdodds.com/blog/state-colocation-will-make-your-react-app-faster&quot; rel=&quot;nofollow&quot;&gt;有关 &lt;code class=&quot;notranslate&quot;&gt;colocation&lt;/code&gt; 的建议&lt;/a&gt;时。然而，在一些使用案例中，性能肯定会出现问题。当你遇到与状态有关的性能问题时，首先要检查的是有多少组件由于状态变化而被重新渲染，并确定这些组件是否真的需要由于该状态变化而被重新渲染。如果是这样，那么问题就不在于你的状态管理机制，而在于你的渲染速度，在这种情况下你需要&lt;a href=&quot;https://kentcdodds.com/blog/fix-the-slow-render-before-you-fix-the-re-render&quot; rel=&quot;nofollow&quot;&gt;加快渲染速度&lt;/a&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;然而，如果你注意到有很多组件在渲染时没有DOM更新或只是需要副作用，那么这些组件就在进行不必要的渲染。这种情况在React中经常发生，而且它本身通常不是一个问题（你应该首先&lt;a href=&quot;https://kentcdodds.com/blog/fix-the-slow-render-before-you-fix-the-re-render&quot; rel=&quot;nofollow&quot;&gt;专注于快速不必要的重新渲染&lt;/a&gt;），但如果它真的是瓶颈，那么这里有一些方法可以解决React上下文中状态的性能问题。&lt;/p&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;把你的状态分成不同的逻辑部分，而不是在一个大的 Store 中，所以对状态的任何部分的单一更新都不会触发对你的应用程序中的每个组件的更新。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kentcdodds.com/blog/how-to-use-react-context-effectively&quot; rel=&quot;nofollow&quot;&gt;优化 Context provider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;引入 &lt;a href=&quot;https://github.com/react-spring/jotai&quot;&gt;jotai&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=&quot;auto&quot;&gt;又来了，又是对一个库的推荐。的确，有一些场景并不适合用 React 内置的状态管理抽象。在所有可用的抽象中，jotai 对于这些场景是最有希望解决的。如果你想知道这些场景是什么，jotai 能很好地解决的什么样的问题，查看： &lt;a href=&quot;https://www.youtube.com/watch?v=_ISAA_Jt9kI&quot; rel=&quot;nofollow&quot;&gt;Recoil 现代 React 的状态管理 - Dave McCabe aka @mcc_abe 在 @ReactEurope 2020&lt;/a&gt; 。Recoil 和 jotai 非常相似（并且解决相同类型的问题）。但根据我对它们的（有限的）经验，我更喜欢jotai。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;在任何情况下，大多数应用程序都不需要像 recoil 或 jotai 这样的原子状态管理工具。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;同样也你可以用 Class Component 做相同的事情, 但 Hooks 使它更容易管理。 你完全可以用 React 15 实现这一理念，没有任何问题。但注意尽可能地保持状态在需要它的地方，只有在 &lt;code class=&quot;notranslate&quot;&gt;Prop Drilling&lt;/code&gt; 真正成为一个问题的时候再考虑使用 &lt;code class=&quot;notranslate&quot;&gt;Context&lt;/code&gt;, 这样做会让你更容易管理状态。&lt;/p&gt;</content>
</entry>
<entry>
<title>React Hooks 中使用 setInterval</title>
<link href="https://tech.jinshuju.net/posts/3/"/>
<id>https://tech.jinshuju.net/posts/3/</id>
<published>2021-08-02T15:51:16Z</published>
<updated>2021-08-03T03:24:14Z</updated>
<author><name>silverWolf818</name></author>
<category term="frontend"/>
<category term="React"/>
<category term="translation"/>
<content type="html">&lt;h2 dir=&quot;auto&quot;&gt;一、困惑&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;在 React Hooks 中我们使用 &lt;code class=&quot;notranslate&quot;&gt;setInterval&lt;/code&gt; 有时会偏离自己想要的效果，给我们来带一些困惑。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;然而我们发现这并不是 React Hooks 的问题，而是 React 编程模式和 &lt;code class=&quot;notranslate&quot;&gt;setInterval&lt;/code&gt; 不匹配造成的。React Hooks 函数式的方式更贴近 React 编程模型，而 &lt;code class=&quot;notranslate&quot;&gt;setInterval&lt;/code&gt; 更符合命令式编程。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;那么我们就来深入分析一下如何在 React Hooks 中使用 &lt;code class=&quot;notranslate&quot;&gt;setInterval&lt;/code&gt;。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;二、尝试&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;首先我们从一个只渲染初始状态的简单例子开始，代码如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Counter&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;接下我们添加一个每秒增加的 interval，它是一个需要清理副作用的，所以我将用到 &lt;code class=&quot;notranslate&quot;&gt;useEffect()&lt;/code&gt; 并返回清理函数，代码如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Counter&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-en&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;clearInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://codesandbox.io/s/crazy-goldwasser-tiejd&quot; rel=&quot;nofollow&quot;&gt;代码地址&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这样工作看起来很简单对吧，似乎也没什么问题。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;默认情况下，React 会在每次渲染后重执行 effects，这是有目的的，这有助于避免 React class 组件的&lt;a href=&quot;https://zh-hans.reactjs.org/docs/hooks-effect.html#explanation-why-effects-run-on-each-update&quot; rel=&quot;nofollow&quot;&gt;某种 bugs&lt;/a&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这通常是好的，因为需要许多订阅 API 可以随时顺手移除老的监听者和加个新的。但是，&lt;code class=&quot;notranslate&quot;&gt;setInterval&lt;/code&gt; 和它们不一样。当我们执行 &lt;code class=&quot;notranslate&quot;&gt;clearInterval&lt;/code&gt; 和 &lt;code class=&quot;notranslate&quot;&gt;setInterval&lt;/code&gt; 时，它们会进入时间队列里，如果我们频繁重渲染和重执行 effects，interval 有可能没有机会被执行！&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;例如我们可以通过以更短间隔重渲染我们的组件，来发现这个 bug，代码如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-en&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;clearInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;App&quot;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;Hello CodeSandbox&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-v&quot;&gt;Counter&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://codesandbox.io/s/throbbing-monad-1zv98&quot; rel=&quot;nofollow&quot;&gt;代码地址&lt;/a&gt;&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;三、继续尝试&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;我们都知道 &lt;code class=&quot;notranslate&quot;&gt;useEffect()&lt;/code&gt; 允许我们选择性地进行重执行 effects，我们可以设定一个依赖数组作为第二个参数，React 只会在数组里的某个发生变化时重运行。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;我们的问题是重运行 effects 时使得 timer 过早被清除，我们可以尝试不重运行去修复它们：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Counter&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-en&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;clearInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;但是，我们发现计时器更新到 1 就不动了。（&lt;a href=&quot;https://codesandbox.io/s/nervous-bhaskara-iqrme&quot; rel=&quot;nofollow&quot;&gt;代码地址&lt;/a&gt;）&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这中间发生了什么❓ 🤔&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这个问题在于，&lt;code class=&quot;notranslate&quot;&gt;useEffect&lt;/code&gt; 在第一次渲染时获取值为 0 的 &lt;code class=&quot;notranslate&quot;&gt;count&lt;/code&gt;，我们不再重执行 &lt;code class=&quot;notranslate&quot;&gt;effect&lt;/code&gt;，所以 &lt;code class=&quot;notranslate&quot;&gt;setInterval&lt;/code&gt; 一直引用第一次渲染时的闭包 &lt;code class=&quot;notranslate&quot;&gt;count&lt;/code&gt;，以至于 &lt;code class=&quot;notranslate&quot;&gt;count + 1&lt;/code&gt; 一直是 1。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;修复它的方式就是使用&lt;a href=&quot;https://zh-hans.reactjs.org/docs/hooks-reference.html#functional-updates&quot; rel=&quot;nofollow&quot;&gt;函数式更新&lt;/a&gt;，就像 &lt;code class=&quot;notranslate&quot;&gt;setCount(c =&amp;gt; c + 1)&lt;/code&gt; 这样替换 &lt;code class=&quot;notranslate&quot;&gt;setCount(count + 1)&lt;/code&gt;，这样可以读到新 &lt;code class=&quot;notranslate&quot;&gt;state&lt;/code&gt; 变量。但这个无法帮助你获取到新的 &lt;code class=&quot;notranslate&quot;&gt;props&lt;/code&gt;。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;四、React Hooks 和 setInterval 的差异&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;我们总想是在 React 编程模式和命令式 &lt;code class=&quot;notranslate&quot;&gt;setInterval&lt;/code&gt; 之间寻找平衡点，想让它们融合在一起工作。但其实它们存在一些模式不匹配。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;一个 React 组件可能在 mounted 之前流经许多不同的 state，但它的渲染结果将一次性全部描述出来。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;// 描述每次渲染&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;Hooks 使我们把相同的声明方法用在 effects 上：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-en&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;clearInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;相反，&lt;code class=&quot;notranslate&quot;&gt;setInterval&lt;/code&gt; 没有及时地描述过程，一旦设定了 interval，除了清除它，你无法对它做任何改变。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这就是 React 编程模式和 &lt;code class=&quot;notranslate&quot;&gt;setInterval&lt;/code&gt; 之间的不匹配。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;strong&gt;差异的体现&lt;/strong&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;React 组件中的 &lt;code class=&quot;notranslate&quot;&gt;props&lt;/code&gt; 和 &lt;code class=&quot;notranslate&quot;&gt;state&lt;/code&gt; 是可以改变的， React 会重渲染它们且丢弃任何关于上一次渲染的结果，它们之间不再有相关性。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;useEffect()&lt;/code&gt; Hook 也丢弃上一次渲染结果，它会清除上一次 effect 再建立下一个 effect，下一个 effect 产生新的 &lt;code class=&quot;notranslate&quot;&gt;props&lt;/code&gt; 和 &lt;code class=&quot;notranslate&quot;&gt;state&lt;/code&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;但 &lt;code class=&quot;notranslate&quot;&gt;setInterval&lt;/code&gt; 不会丢弃。 它会一直引用老的 &lt;code class=&quot;notranslate&quot;&gt;props&lt;/code&gt; 和 &lt;code class=&quot;notranslate&quot;&gt;state&lt;/code&gt; 直到你把它换掉。（不重置时间你是无法做到的）&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;五、Refs 方案&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;首先我们先总结一下问题：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;我们在第一次渲染时执行带 &lt;code class=&quot;notranslate&quot;&gt;callback1&lt;/code&gt; 的 &lt;code class=&quot;notranslate&quot;&gt;setInterval(callback1, delay)&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;我们在下一次渲染时得到携带新的 &lt;code class=&quot;notranslate&quot;&gt;props&lt;/code&gt; 和 &lt;code class=&quot;notranslate&quot;&gt;state&lt;/code&gt; 的 &lt;code class=&quot;notranslate&quot;&gt;callback2&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;我们无法在不重置时间的情况下替换掉已经存在的 interval。&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;那么如果我们根本不替换 interval，而是引入一个指向新 interval 回调的可变 savedCallback 会怎么样？现在我们来看看这个方案：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;我们调用 &lt;code class=&quot;notranslate&quot;&gt;setInterval(fn, delay)&lt;/code&gt;，其中 &lt;code class=&quot;notranslate&quot;&gt;fn&lt;/code&gt; 调用 &lt;code class=&quot;notranslate&quot;&gt;savedCallback&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;第一次渲染后将 &lt;code class=&quot;notranslate&quot;&gt;savedCallback&lt;/code&gt; 设为 &lt;code class=&quot;notranslate&quot;&gt;callback1&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;下一次渲染后将 &lt;code class=&quot;notranslate&quot;&gt;savedCallback&lt;/code&gt; 设为 &lt;code class=&quot;notranslate&quot;&gt;callback2&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;重复上面的步骤，完成。&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;那么这个可变的 &lt;code class=&quot;notranslate&quot;&gt;savedCallback&lt;/code&gt; 需要在重新渲染时&lt;strong&gt;可持续&lt;/strong&gt;，所以不可以是一个常规变量，我们想要一个类似对象的变量。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这时我们会想到使用 &lt;a href=&quot;https://zh-hans.reactjs.org/docs/hooks-reference.html#useref&quot; rel=&quot;nofollow&quot;&gt;useRef()&lt;/a&gt; 这个 Hooks。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt; &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;savedCallback&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;useRef&lt;/code&gt; 返回一个可变的 ref 普通对象在 render 间共享。我们可以保存新的 interval 回掉给它：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;pl-c&quot;&gt;// 可以读到新 props，state等。&lt;/span&gt;
   &lt;span class=&quot;pl-en&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-c&quot;&gt;// 每次渲染后，保存新的回调到我们的 ref 里。&lt;/span&gt;
&lt;span class=&quot;pl-en&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;pl-s1&quot;&gt;savedCallback&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;current&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;之后我们便可以从我们的 interval 中读取和调用它：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-en&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;tick&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-s1&quot;&gt;savedCallback&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;tick&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;clearInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;这里 &lt;code class=&quot;notranslate&quot;&gt;[]&lt;/code&gt;，不重执行我们的 effect，interval 就不会被重置。同时 &lt;code class=&quot;notranslate&quot;&gt;savedCallback&lt;/code&gt; ref，让我们可以一直在新渲染之后读取到回调，并在 interval tick 里调用它。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;完整的代码如下：&lt;a href=&quot;https://codesandbox.io/s/ecstatic-elgamal-bkjcb&quot; rel=&quot;nofollow&quot;&gt;代码地址&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Counter&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;savedCallback&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;pl-en&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;savedCallback&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;current&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-en&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;tick&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;savedCallback&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;tick&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;clearInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;到这里我们就让 React Hooks 和 &lt;code class=&quot;notranslate&quot;&gt;setInterval&lt;/code&gt; 完美的运行在了一起。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;六、自定义 useInterval&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;上述代码如果直接使用会比较麻烦，于是我们就提取一个 custom Hook，例如 &lt;code class=&quot;notranslate&quot;&gt;useInterval&lt;/code&gt;，代码如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;savedCallback&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-en&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;savedCallback&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;current&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-en&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;tick&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;pl-s1&quot;&gt;savedCallback&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;tick&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;clearInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;我们还可以添加一个 &lt;code class=&quot;notranslate&quot;&gt;delay&lt;/code&gt; 参数，来调整时间间隔，当 &lt;code class=&quot;notranslate&quot;&gt;delay&lt;/code&gt; 改变时，我们重新生成一个 timer。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;我们只需要在组件中这样使用即可：&lt;a href=&quot;https://codesandbox.io/s/festive-rosalind-nux60&quot; rel=&quot;nofollow&quot;&gt;代码地址&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-en&quot;&gt;useInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;App&quot;&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;pl-c1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;strong&gt;添加暂停功能&lt;/strong&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;假设我们希望能够通过传递 &lt;code class=&quot;notranslate&quot;&gt;null&lt;/code&gt; 作为 &lt;code class=&quot;notranslate&quot;&gt;delay&lt;/code&gt; 来暂停我们的 interval，如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setDelay&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;isRunning&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;setIsRunning&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-en&quot;&gt;useInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;setCount&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-s1&quot;&gt;isRunning&lt;/span&gt; ? &lt;span class=&quot;pl-s1&quot;&gt;delay&lt;/span&gt; : &lt;span class=&quot;pl-c1&quot;&gt;null&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;然后我们修改一下 &lt;code class=&quot;notranslate&quot;&gt;useInterval&lt;/code&gt; 的代码，如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-en&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;tick&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;savedCallback&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;pl-k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;delay&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;tick&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;clearInterval&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;到此我们的 custom Hook 也编写完成。&lt;a href=&quot;https://codesandbox.io/s/patient-worker-5tq1s&quot; rel=&quot;nofollow&quot;&gt;代码地址&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p dir=&quot;auto&quot;&gt;原文链接：&lt;a href=&quot;https://overreacted.io/making-setinterval-declarative-with-react-hooks/&quot; rel=&quot;nofollow&quot;&gt;Making setInterval Declarative with React Hooks&lt;/a&gt;&lt;/p&gt;</content>
</entry>
<entry>
<title>polyfill in create-react-app</title>
<link href="https://tech.jinshuju.net/posts/2/"/>
<id>https://tech.jinshuju.net/posts/2/</id>
<published>2021-07-13T16:18:05Z</published>
<updated>2021-08-03T00:46:34Z</updated>
<author><name>silverWolf818</name></author>
<category term="frontend"/>
<content type="html">&lt;h2 dir=&quot;auto&quot;&gt;一、create-react-app 中的 polyfill&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;上一篇我们已经了解了如何使用 Babel 进行 polyfill。现在我们基于 React 工程来实践。&lt;/p&gt;
&lt;h3 dir=&quot;auto&quot;&gt;1. 创建工程&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;这里使用官方的脚手架工具初始化项目，如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;yarn create react-app react-polyfill&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;我们需要修改 Babel 配置，还需要运行如下命令：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;yarn eject&lt;/pre&gt;&lt;/div&gt;
&lt;h3 dir=&quot;auto&quot;&gt;2. 查看 Babel 配置&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;在 &lt;code class=&quot;notranslate&quot;&gt;webpack.config.js&lt;/code&gt; 文件中，找到对应解析 js 的 loader 配置如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;// ... code&lt;/span&gt;
presets: &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;pl-en&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'babel-preset-react-app'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;pl-c1&quot;&gt;runtime&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot;&gt;hasJsxRuntime&lt;/span&gt; ? &lt;span class=&quot;pl-s&quot;&gt;'automatic'&lt;/span&gt; : &lt;span class=&quot;pl-s&quot;&gt;'classic'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;pl-c&quot;&gt;// ... code    &lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;观察源码发现，官方提供的 presets 是 &lt;code class=&quot;notranslate&quot;&gt;babel-preset-react-app&lt;/code&gt; 而不是我们所熟悉的 &lt;code class=&quot;notranslate&quot;&gt;@babel/preset-env&lt;/code&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;babel-preset-react-app&lt;/code&gt; 其实是 React 官方封装的一个库。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;查看 &lt;code class=&quot;notranslate&quot;&gt;babel-preset-react-app&lt;/code&gt; 找到对应的 preset 设置，对应源码中 &lt;code class=&quot;notranslate&quot;&gt;create.js&lt;/code&gt; 文件，如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;isEnvProduction&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;isEnvDevelopment&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;pl-c&quot;&gt;// Latest stable ECMAScript features&lt;/span&gt;
  &lt;span class=&quot;pl-en&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'@babel/preset-env'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-c&quot;&gt;// Allow importing core-js in entrypoint and use browserlist to select polyfills&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;useBuiltIns&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;'entry'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-c&quot;&gt;// Set the corejs version we are using to avoid warnings in console&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;corejs&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-c&quot;&gt;// Exclude transforms that make all code slower&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;exclude&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'transform-typeof-symbol'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;看到这里就一目了然了，根据上一篇我们了解到的知识。&lt;code class=&quot;notranslate&quot;&gt;@babel/preset-env&lt;/code&gt; 参数是 &lt;code class=&quot;notranslate&quot;&gt;useBuiltIns: 'entry'&lt;/code&gt; 和 &lt;code class=&quot;notranslate&quot;&gt;corejs: 3&lt;/code&gt;，那么就需要我们手动导入对应的 polyfill 文件。这里对应的源码注释也说得非常详细。&lt;/p&gt;
&lt;h3 dir=&quot;auto&quot;&gt;3. 进行 polyfill&lt;/h3&gt;
&lt;p dir=&quot;auto&quot;&gt;首先安装 &lt;code class=&quot;notranslate&quot;&gt;corejs3&lt;/code&gt; 和 &lt;code class=&quot;notranslate&quot;&gt;regenerator-runtime&lt;/code&gt; 依赖，如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;yarn add core-js@3 regenerator-runtime&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;然后在 &lt;code class=&quot;notranslate&quot;&gt;src&lt;/code&gt; 目录下，创建一个 &lt;code class=&quot;notranslate&quot;&gt;polyfill/index.js&lt;/code&gt;，在文件中导入我们需要 polyfill 的 API，如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'core-js/es/array/flat'&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'core-js/es/array/flat-map'&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'core-js/es/array/includes'&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'regenerator-runtime/runtime'&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;我们有 2 种方式引入 polyfill：&lt;/p&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;直接在入口文件引入 &lt;code class=&quot;notranslate&quot;&gt;index.js&lt;/code&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'./polyfill/index.js'&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;2&quot; dir=&quot;auto&quot;&gt;
&lt;li&gt;在 &lt;code class=&quot;notranslate&quot;&gt;webpack.config.js&lt;/code&gt; 中的 &lt;code class=&quot;notranslate&quot;&gt;entry&lt;/code&gt; 参数中添加：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;entry:&lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;pl-c&quot;&gt;// ... code&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;appPolyFillJs&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-s1&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;appIndexJs&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-c&quot;&gt;// ... code&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;   &lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;然后我们启动工程，找到编译后的文件如下：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/ea28467ea59779286dcad596161c4b3904c7b34b4f3375fda11deafc36d0c047/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d32303231303731323137333335373732342d313632363130333233363931322e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/ea28467ea59779286dcad596161c4b3904c7b34b4f3375fda11deafc36d0c047/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d32303231303731323137333335373732342d313632363130333233363931322e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-20210712173357724-1626103236912.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;通过上述的配置方法就实现了 polyfill，这也算是官方推荐的一个方案。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;二、按需加载&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;如果我们想要实现按需加载怎么办？&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;那么我们就从 Github 上 fork 一份 &lt;a href=&quot;https://github.com/facebook/create-react-app/tree/main/packages/babel-preset-react-app&quot;&gt;babel-preset-react-app&lt;/a&gt; 源码。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;其他步骤和之前介绍过的一样，只需要修改 &lt;code class=&quot;notranslate&quot;&gt;create.js&lt;/code&gt; 的 preset 即可，如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;target&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;chrome&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;61&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;firefox&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;52&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;safari&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;pl-c1&quot;&gt;ie&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;11&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;useBuiltIns&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;'usage'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;corejs&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;exclude&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'transform-typeof-symbol'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;然后发布到 npm 仓库，修改 &lt;code class=&quot;notranslate&quot;&gt;webpack.config.js&lt;/code&gt; 文件中 loader 替换成自己的。如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;// code ...&lt;/span&gt;
presets: &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;pl-en&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'xxxx/babel-preset-react-app'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;pl-c&quot;&gt;// code ...&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/ea28467ea59779286dcad596161c4b3904c7b34b4f3375fda11deafc36d0c047/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d32303231303731323137333335373732342d313632363130333233363931322e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/ea28467ea59779286dcad596161c4b3904c7b34b4f3375fda11deafc36d0c047/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d32303231303731323137333335373732342d313632363130333233363931322e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-20210712173357724-1626103236912.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;以上就是通过 create-react-app 创建工程的 polyfill 方法。如果自己使用 &lt;code class=&quot;notranslate&quot;&gt;webpack&lt;/code&gt; 搭建就直接修改 preset 就好。&lt;/p&gt;</content>
</entry>
<entry>
<title>一次 polyfill 对 babel 的思考🤔</title>
<link href="https://tech.jinshuju.net/posts/1/"/>
<id>https://tech.jinshuju.net/posts/1/</id>
<published>2021-07-11T13:45:26Z</published>
<updated>2021-08-03T00:46:50Z</updated>
<author><name>silverWolf818</name></author>
<category term="frontend"/>
<content type="html">&lt;h1 dir=&quot;auto&quot;&gt;一、起因&lt;/h1&gt;
&lt;p dir=&quot;auto&quot;&gt;正在写 bug🐛 的我，突然被叫去看一个问题，页面突然白屏了。于是本能的反应是快速打开控制台，发现 js 有报错，报错信息是 &lt;code class=&quot;notranslate&quot;&gt;.flat() is not a function&lt;/code&gt;，原来是浏览器版本不支持 &lt;code class=&quot;notranslate&quot;&gt;flat&lt;/code&gt; API，做一下 polyfill 就好了。那么我们如何 polyfill 呢？🤔 接下来就来详细分析一下 polyfill 的过程。&lt;/p&gt;
&lt;h1 dir=&quot;auto&quot;&gt;二、Babel 的作用&lt;/h1&gt;
&lt;p dir=&quot;auto&quot;&gt;首先在进行 polyfill 之前，我们复习一下 Babel 这个编译器。&lt;a href=&quot;https://www.babeljs.cn/&quot; rel=&quot;nofollow&quot;&gt;官方文档&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;strong&gt;Babel 主要用于将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法，以便能够运行在当前和旧版本的浏览器或其他环境中。&lt;/strong&gt; 作用如下：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;语法转换&lt;/li&gt;
&lt;li&gt;通过 Polyfill 方式在目标环境中添加缺失的特性（通过第三方 polyfill 模块，例如 core-js，实现）&lt;/li&gt;
&lt;li&gt;源码转换 (codemods)&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;换而言之就是 Babel 能让我们现在就使用新的语法，无需等待浏览器的支持。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;看上去很美好，但还是有一些原生 API 方法， Babel 并没用做转换处理，例如：&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/flat&quot; rel=&quot;nofollow&quot;&gt;flat&lt;/a&gt;、&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap&quot; rel=&quot;nofollow&quot;&gt;flatMap&lt;/a&gt;、&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/includes&quot; rel=&quot;nofollow&quot;&gt;includes&lt;/a&gt; 等。这时我们就需要为 Babel 编译器做一些配置，也就是 polyfill。&lt;/p&gt;
&lt;h1 dir=&quot;auto&quot;&gt;三、@babel/polyfill&lt;/h1&gt;
&lt;p dir=&quot;auto&quot;&gt;正常我们使用 Babel 是不需要安装 &lt;code class=&quot;notranslate&quot;&gt;@babel/polyfill&lt;/code&gt;，但是如果我们需要兼容版本较低的浏览器，就可以使用该库。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;@babel/polyfill&lt;/code&gt; 它会模拟完整的 ES2015+ 环境用于我们的程序，这样我们使用的 &lt;code class=&quot;notranslate&quot;&gt;Promise&lt;/code&gt; 或 &lt;code class=&quot;notranslate&quot;&gt;WeakMap&lt;/code&gt; 这样的新内置函数，&lt;code class=&quot;notranslate&quot;&gt;Array.from&lt;/code&gt; 或 &lt;code class=&quot;notranslate&quot;&gt;Object.assign&lt;/code&gt; 这样的静态方法，&lt;code class=&quot;notranslate&quot;&gt;Array.prototype.includes&lt;/code&gt; 这样的实例方法等，会被 polyfill 添加到全局范围。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;使用方法也相对简单，只需要安装 &lt;code class=&quot;notranslate&quot;&gt;@babel/polyfill&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;yarn add @babel/polyfill&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;然后在我们的入口文件引入：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;@babel/polyfill&quot;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;来看一个示例：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;我们编写一个 &lt;code class=&quot;notranslate&quot;&gt;index.js&lt;/code&gt; 文件如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'@babel/polyfill'&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;flat&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;flatMap&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;然后使用 &lt;code class=&quot;notranslate&quot;&gt;webpack&lt;/code&gt; 工具编译，输出后的结果如下：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;截图中红色区域就是我们引入的 &lt;code class=&quot;notranslate&quot;&gt;@babel/polyfill&lt;/code&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/bab07e83488cf846041c8381e3f34bcc0437ca0e9a0a9b4e49c11e279b8b8e21/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313632353839393033353230372e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/bab07e83488cf846041c8381e3f34bcc0437ca0e9a0a9b4e49c11e279b8b8e21/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313632353839393033353230372e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1625899035207.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;@babel/polyfill&lt;/code&gt; 的入口文件，实质上是把  ES2015+ 的 &lt;code class=&quot;notranslate&quot;&gt;polyfill&lt;/code&gt; 和一个 &lt;code class=&quot;notranslate&quot;&gt;runtime&lt;/code&gt; 转译生成器函数引入。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/e0d315b5d8c43233b93658e88f17e72b8cfcccaf7d60438a298ed1bd0f663a8c/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313632353839393138353439392e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/e0d315b5d8c43233b93658e88f17e72b8cfcccaf7d60438a298ed1bd0f663a8c/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313632353839393138353439392e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1625899185499.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这样无疑增加了我们打包的体积，我只使用了 &lt;code class=&quot;notranslate&quot;&gt;flat&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;flatMap&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;includes&lt;/code&gt;，却引入了整个 &lt;code class=&quot;notranslate&quot;&gt;polyfill&lt;/code&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;在新的 Babel 版本（7.4.0）中 &lt;code class=&quot;notranslate&quot;&gt;@babel/polyfill&lt;/code&gt; 已经被废弃，不在推荐使用。这里简单了解一下即可。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://github.com/yaeSakuras/babel-demo/tree/master/package/babel-polyfill&quot;&gt;源码地址&lt;/a&gt;&lt;/p&gt;
&lt;h1 dir=&quot;auto&quot;&gt;四、被遗忘的 core-js&lt;/h1&gt;
&lt;p dir=&quot;auto&quot;&gt;这是什么鬼 👻 ，日常我们更多的可能是使用 &lt;code class=&quot;notranslate&quot;&gt;react&lt;/code&gt; 等库进行前端开发，很少会关注底层的一些依赖，了解它对于我们 &lt;code class=&quot;notranslate&quot;&gt;polyfill&lt;/code&gt; 很重要。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;strong&gt;core-js 是一个 JavaScript 的模块化标准库。包括 ECMAScript 到 2021 年的 polyfill。&lt;/strong&gt; &lt;a href=&quot;https://github.com/zloirock/core-js&quot;&gt;官方文档&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;core-js&lt;/code&gt; 的几个核心概念：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;它尽可能的进行模块化，让你能选择你需要的功能&lt;/li&gt;
&lt;li&gt;它可以不污染全局空间&lt;/li&gt;
&lt;li&gt;它和 babel 高度集成，可以对 &lt;code class=&quot;notranslate&quot;&gt;core-js&lt;/code&gt; 的引入进行最大程度的优化&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;core-js&lt;/code&gt; 目前有 2 个版本，2 和 3 ，由于 3 版本进行了一些破坏性变更导致无法兼容 2 版本，现在 2 版本被废弃使用。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;core-js@3&lt;/code&gt; 的重要改变：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;对于 ECMAScript 中已经稳定的功能，core-js 已经几乎完全支持，并在 &lt;code class=&quot;notranslate&quot;&gt;core-js@3&lt;/code&gt; 中引入了一些新的功能&lt;/li&gt;
&lt;li&gt;对于一些已经加入到 ES2016-ES2019 中的提案，现在已经被标记为稳定功能&lt;/li&gt;
&lt;li&gt;增加了 proposals 配置项，对处在提案阶段的 api 提供支持，但是因为提案阶段并不稳定，在正式加入标准之前，可能会有大的改动，需要谨慎使用；对于一些改变巨大的提案，也进行了对应的更新&lt;/li&gt;
&lt;li&gt;增加了对一些 web 标准的支持，比如 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/URL&quot; rel=&quot;nofollow&quot;&gt;URL&lt;/a&gt; 和 &lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/API/URLSearchParams&quot; rel=&quot;nofollow&quot;&gt;URLSearchParams&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;删除了一些过时的特性&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;由于 &lt;code class=&quot;notranslate&quot;&gt;core-js@2&lt;/code&gt; 版本包的体积太大(~2M)，并且有很多重复的文件被引用。&lt;code class=&quot;notranslate&quot;&gt;core-js@3&lt;/code&gt; 对包进行拆分，三个核心的包分别是：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/zloirock/core-js/tree/master/packages/core-js&quot;&gt;core-js&lt;/a&gt;：定义全局的 polyfill（~500k, 40k minified and gzipped）&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/zloirock/core-js/tree/master/packages/core-js-pure&quot;&gt;core-js-pure&lt;/a&gt;：提供不污染全局环境的 polyfill，等价于 core-js@2/library（~440k）&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/zloirock/core-js/tree/master/packages/core-js-compat&quot;&gt;core-js-compat&lt;/a&gt;：包含了 core-js 模块和 API 必要的数据，通过 browserslist 来生成所需要的 core-js 模块的列表&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;对于 &lt;code class=&quot;notranslate&quot;&gt;core-js@3&lt;/code&gt; 的入口文件，我们可以这样使用：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;// polyfill all `core-js` features:&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;core-js&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-c&quot;&gt;// polyfill only stable `core-js` features - ES and web standards:&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;core-js/stable&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-c&quot;&gt;// polyfill only stable ES features:&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;core-js/es&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-c&quot;&gt;// if you want to polyfill `Set`:&lt;/span&gt;
&lt;span class=&quot;pl-c&quot;&gt;// all `Set`-related features, with ES proposals:&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;core-js/features/set&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-c&quot;&gt;// stable required for `Set` ES features and features from web standards&lt;/span&gt;
&lt;span class=&quot;pl-c&quot;&gt;// (DOM collections iterator in this case):&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;core-js/stable/set&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-c&quot;&gt;// only stable ES features required for `Set`:&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;core-js/es/set&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-c&quot;&gt;// the same without global namespace pollution:&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;core-js-pure/features/set&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;core-js-pure/stable/set&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Set&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;core-js-pure/es/set&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-c&quot;&gt;// if you want to polyfill just required methods:&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;core-js/features/set/intersection&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;core-js/stable/queue-microtask&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;core-js/es/array/from&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;我们还可以使用 &lt;code class=&quot;notranslate&quot;&gt;core-js-compat&lt;/code&gt; 用来提供不用目标引擎所需要的core-js的模块信息：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  list&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;              &lt;span class=&quot;pl-c&quot;&gt;// array of required modules&lt;/span&gt;
  targets&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;           &lt;span class=&quot;pl-c&quot;&gt;// object with targets for each module&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;'core-js-compat'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;targets&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;'&amp;gt; 2.5%'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c&quot;&gt;// browserslist query&lt;/span&gt;
  &lt;span class=&quot;pl-c1&quot;&gt;filter&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;'es.'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;     &lt;span class=&quot;pl-c&quot;&gt;// optional filter - string-prefix, regexp or list of modules&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;pl-smi&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1 dir=&quot;auto&quot;&gt;五、了解 browserslist&lt;/h1&gt;
&lt;p dir=&quot;auto&quot;&gt;我们使用 React 开发，在 &lt;code class=&quot;notranslate&quot;&gt;package.json&lt;/code&gt; 中有这么一段配置：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-json&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-ent&quot;&gt;&quot;browserslist&quot;&lt;/span&gt;: {
  &lt;span class=&quot;pl-ent&quot;&gt;&quot;production&quot;&lt;/span&gt;: [
    &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&amp;gt;0.2%&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
    &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;not dead&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
    &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;not op_mini all&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  ],
  &lt;span class=&quot;pl-ent&quot;&gt;&quot;development&quot;&lt;/span&gt;: [
    &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;last 1 chrome version&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
    &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;last 1 firefox version&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
    &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;last 1 safari version&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  ]
}&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;或在根目录存在一个 &lt;code class=&quot;notranslate&quot;&gt;.browserslistrc&lt;/code&gt; 的配置文件。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;那么这个 &lt;code class=&quot;notranslate&quot;&gt;browserslist&lt;/code&gt; 有什么用呢？&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;browserslist&lt;/code&gt; 能在不同前端工具之间共享目标浏览器和 Node.js 版本的配置。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;browserslist&lt;/code&gt; 使用 &lt;a href=&quot;https://www.npmjs.com/package/caniuse-lite&quot; rel=&quot;nofollow&quot;&gt;caniuse-lite&lt;/a&gt; 和 &lt;a href=&quot;https://caniuse.com/&quot; rel=&quot;nofollow&quot;&gt;caniuse&lt;/a&gt; 进行查询。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;那么我们如何知道这个配置都兼容是什么，官方也提供了查询。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;例如我们有如下配置：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-json&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-ent&quot;&gt;&quot;browserslist&quot;&lt;/span&gt;: [
  &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&amp;gt;0.2%&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;not dead&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;not op_mini all&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
]&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;然后运行：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;npx browserslist&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;输出：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/d54a1b83b88e689d56d83d79d5714b7e5c3fc0bcf13a0e998e80e5c591131a85/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313632353930363639303138302e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/d54a1b83b88e689d56d83d79d5714b7e5c3fc0bcf13a0e998e80e5c591131a85/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313632353930363639303138302e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1625906690180.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;这个配置的大概意思：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;&amp;gt;0.2%&lt;/code&gt;：拥有至少 0.2% 全球市场份额的所有浏览器&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;not dead&lt;/code&gt;：排除过去 24 个月内没有官方支持的浏览器&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;not op_mini all&lt;/code&gt; 排除 Opera Mini 浏览器&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;这里不做过多的展开，有兴趣的可以查看。 &lt;a href=&quot;https://github.com/browserslist/browserslist&quot;&gt;官网文档&lt;/a&gt;&lt;/p&gt;
&lt;h1 dir=&quot;auto&quot;&gt;六、了解 @babel/preset-env&lt;/h1&gt;
&lt;p dir=&quot;auto&quot;&gt;前面花了这么多篇幅介绍相关的工具和库，都是为了介绍 &lt;code class=&quot;notranslate&quot;&gt;@babel/preset-env&lt;/code&gt; 做铺垫，&lt;code class=&quot;notranslate&quot;&gt;@babel/preset-env&lt;/code&gt; 可以说是我们做 polyfill 的核心包。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;@babel/preset-env&lt;/code&gt; 是什么呢？&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://github.com/babel/babel/tree/master/packages/babel-preset-env&quot;&gt;官网文档&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;首先，介绍历史背景，对了解和学习 &lt;code class=&quot;notranslate&quot;&gt;@babel/preset-env&lt;/code&gt; 有帮助。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;最初，为了让开发者能够尽早用上新的 ES 特性，babel 团队开发了 &lt;a href=&quot;https://www.npmjs.com/package/babel-preset-latest&quot; rel=&quot;nofollow&quot;&gt;babel-preset-latest&lt;/a&gt;。这个 preset 比较特殊，它是多个 preset 的集合(es2015+)，并且随着 ECMA 规范的更新更增加它的内容。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;比如(2018.06.02)，它包含的 preset 包括：es2017、es1016、es2015。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;到了明年，可能它包含的 preset 就包括：es2020、es2019、es2018、es2017、es2016、es2015。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;随着时间的推移，babel-preset-latest 包含的插件越来越多，这带来了如下问题：&lt;/p&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;加载的插件越来越多，编译速度会越来越慢；&lt;/li&gt;
&lt;li&gt;随着用户浏览器的升级，ECMA 规范的支持逐步完善，编译至低版本规范的必要性在减少（比如ES6 -&amp;gt; ES5），多余的转换不单降低执行效率，还浪费带宽。&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=&quot;auto&quot;&gt;因为上述问题的存在，babel 官方推出了 &lt;code class=&quot;notranslate&quot;&gt;@babel/preset-env&lt;/code&gt; 插件。它可以根据开发者的配置，按需加载插件。配置项大致包括：&lt;/p&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;需要支持的平台：比如node、浏览器等。&lt;/li&gt;
&lt;li&gt;需要支持的平台的版本：比如支持 node@6.1等。&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=&quot;auto&quot;&gt;一句话解释：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;@babel/preset-env 可以根据配置的目标浏览器或者运行环境来自动将 ES2015+ 的代码转换为 es5。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;其实它和 Babel 做的事情有部分是重叠，由于 Babel 还有编译等核心功能，所有对于 ECMA 规范的预设就交给了  &lt;code class=&quot;notranslate&quot;&gt;@babel/preset-env&lt;/code&gt; 专门处理。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;@babel/preset-env&lt;/code&gt; 与 core-js 和 browserslist 搭配，共同完成 ECMA 语法规范的预设。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;接下来到我们的实践环节。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;在开始我们的实践之前，先声明在 babel7.4.0 的版本中已经支持 core-js@3 的版本。core-js@3 的出现，也迫使我们放弃 &lt;code class=&quot;notranslate&quot;&gt;@babel/polyfill&lt;/code&gt; (只支持 core-js2)。&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;polyfill 的第一种方式&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;先准备环境，安装 babel 核心库和 &lt;code class=&quot;notranslate&quot;&gt;@babel/preset-env&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;yarn add @babel/core @babel/cli @babel/preset-env --save-dev&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;由于我们废弃了 &lt;code class=&quot;notranslate&quot;&gt;@babel/polyfill&lt;/code&gt;，需安装 core-js@3 和 regenerator-runtime&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;yarn add core-js@3 regenerator-runtime&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;添加 &lt;code class=&quot;notranslate&quot;&gt;babel.config.json&lt;/code&gt; 配置文件：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-json&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;{
  &lt;span class=&quot;pl-ent&quot;&gt;&quot;presets&quot;&lt;/span&gt;: [
    [
      &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@babel/reset-env&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
      {
        &lt;span class=&quot;pl-ent&quot;&gt;&quot;useBuiltIns&quot;&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;entry&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
        &lt;span class=&quot;pl-ent&quot;&gt;&quot;corejs&quot;&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;3&lt;/span&gt;
      }
    ]
  ]
}&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;在 &lt;code class=&quot;notranslate&quot;&gt;package.json&lt;/code&gt; 中添加 &lt;code class=&quot;notranslate&quot;&gt;browserslist&lt;/code&gt; 配置：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-json&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-ent&quot;&gt;&quot;browserslist&quot;&lt;/span&gt;: [
    &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&amp;gt; 0.02%&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
    &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;not dead&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  ]&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;添加我们的测试代码：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;// a.js&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;flatFn&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;flat&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;flatMap&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;flatMap&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-c&quot;&gt;// b.js&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;pl-k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pl-v&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;resolve&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;wait&lt;/span&gt;

&lt;span class=&quot;pl-c&quot;&gt;// index.js&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'core-js/stable'&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'regenerator-runtime/runtime'&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;flatFn&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;flatMap&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'./a'&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;wait&lt;/span&gt; &lt;span class=&quot;pl-k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'./b'&lt;/span&gt;

&lt;span class=&quot;pl-k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;pl-en&quot;&gt;flatFn&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-en&quot;&gt;flatMap&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-en&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pl-en&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;pl-s1&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;这里需要注意我们在入口 &lt;code class=&quot;notranslate&quot;&gt;index.js&lt;/code&gt; 中，引入了 &lt;code class=&quot;notranslate&quot;&gt;core-js/stable&lt;/code&gt; 和 &lt;code class=&quot;notranslate&quot;&gt;regenerator-runtime/runtime&lt;/code&gt;，因为我们废弃了 &lt;code class=&quot;notranslate&quot;&gt;@babel/polyfill&lt;/code&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;然后运行脚本：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;yarn build&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;编译之后它把所有的 polyfill 注入到我们的入口文件中，截取部分代码如图所示：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/7c5ea860573dc6d7e3ad41a57f20412a13ded55218ef84705002e38fc22050f6/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313632363030363237383437352e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/7c5ea860573dc6d7e3ad41a57f20412a13ded55218ef84705002e38fc22050f6/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313632363030363237383437352e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1626006278475.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;接下来，重点讲一下 babel 配置文件中的 &lt;code class=&quot;notranslate&quot;&gt;useBuiltIns&lt;/code&gt; 这个参数：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-s&quot;&gt;&quot;usage&quot;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;&quot;entry&quot;&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;defaults&lt;/span&gt; &lt;span class=&quot;pl-s1&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;.&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;entry&lt;/code&gt;：将 &lt;code class=&quot;notranslate&quot;&gt;import 'core-js'&lt;/code&gt; 和 &lt;code class=&quot;notranslate&quot;&gt;import 'regenerator-runtime'&lt;/code&gt; ，替换（或打散）为适配目标环境的各个引用。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-c&quot;&gt;// app.js&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'core-js/stable'&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;pl-k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-s&quot;&gt;'regenerator-runtime/runtime'&lt;/span&gt;

&lt;span class=&quot;pl-c&quot;&gt;// babel-loader options&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;pl-s&quot;&gt;&quot;presets&quot;&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;pl-s&quot;&gt;&quot;@babel/env&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-s&quot;&gt;&quot;useBuiltIns&quot;&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&quot;entry&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;pl-s&quot;&gt;&quot;corejs&quot;&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;pl-s&quot;&gt;&quot;targets&quot;&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;pl-s&quot;&gt;&quot;browsers&quot;&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;pl-s&quot;&gt;&quot;last 2 versions&quot;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;pl-s&quot;&gt;&quot;not ie &amp;lt;= 10&quot;&lt;/span&gt;
          &lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;usage&lt;/code&gt;：每个文件中使用 polyfill 时，为它们添加导入。也就是按需加载。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;注意！ 使用 &lt;code class=&quot;notranslate&quot;&gt;usage&lt;/code&gt; 时，不需要手动导入 corejs | regenerator-runtime，否则会提示错误&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;修改一下我们之前的 babel 配置文件，如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-json&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;{
  &lt;span class=&quot;pl-ent&quot;&gt;&quot;presets&quot;&lt;/span&gt;: [
    [
      &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@babel/env&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
      {
        &lt;span class=&quot;pl-ent&quot;&gt;&quot;useBuiltIns&quot;&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;usage&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
        &lt;span class=&quot;pl-ent&quot;&gt;&quot;corejs&quot;&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;3&lt;/span&gt;
      }
    ]
  ]
}&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;他会为我们每一个文件添加 polyfill。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;修改我们的 &lt;code class=&quot;notranslate&quot;&gt;webpack&lt;/code&gt; 配置：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-js&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-s1&quot;&gt;rules&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;test&lt;/span&gt;: &lt;span class=&quot;pl-pds&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;pl-cce&quot;&gt;\.&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;pl-cce&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
         &lt;span class=&quot;pl-c&quot;&gt;// useBuiltIns: 'usage' 时设置&lt;/span&gt;
         &lt;span class=&quot;pl-c&quot;&gt;// 这里排除了 core-js,webpack/buildin ，否则会报错，因为babel默认会将corejs自身也进行编译&lt;/span&gt;
         &lt;span class=&quot;pl-c&quot;&gt;// https://github.com/zloirock/core-js/issues/743&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;exclude&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;pl-pds&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;pl-cce&quot;&gt;\b&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;pl-cce&quot;&gt;\b&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;pl-pds&quot;&gt;&lt;span class=&quot;pl-c1&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;pl-cce&quot;&gt;\b&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;pl-cce&quot;&gt;\/&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;pl-s&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;pl-cce&quot;&gt;\b&lt;/span&gt;&lt;span class=&quot;pl-c1&quot;&gt;/&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;pl-c1&quot;&gt;use&lt;/span&gt;: &lt;span class=&quot;pl-kos&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;pl-c1&quot;&gt;loader&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;'babel-loader'&lt;/span&gt;
        &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;pl-kos&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;pl-kos&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;pl-kos&quot;&gt;,&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;然后我们编译一下，现在按需加载，体积减少很多。截取部分代码如图所示：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/a7b412235ac846ac444c751ec72b6fa529555dbcf98dc3bc66e2f14346854a3e/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313632363030363339363739382e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/a7b412235ac846ac444c751ec72b6fa529555dbcf98dc3bc66e2f14346854a3e/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313632363030363339363739382e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1626006396798.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;&lt;code class=&quot;notranslate&quot;&gt;false&lt;/code&gt;: 不会像 &lt;code class=&quot;notranslate&quot;&gt;usage&lt;/code&gt; 为每个文件添加 polyfill；也不会像 &lt;code class=&quot;notranslate&quot;&gt;entry&lt;/code&gt;，将 &lt;code class=&quot;notranslate&quot;&gt;import 'core-js'&lt;/code&gt; &lt;code class=&quot;notranslate&quot;&gt;import 'regenerator-runtime'&lt;/code&gt; 替换为适配目标环境的各个引用。对在入口文件引入的 polyfill 不做任何处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;修改一下我们 babel 配置文件，如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-json&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;{
  &lt;span class=&quot;pl-ent&quot;&gt;&quot;presets&quot;&lt;/span&gt;: [
    [
      &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@babel/preset-env&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
      {
        &lt;span class=&quot;pl-ent&quot;&gt;&quot;useBuiltIns&quot;&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;false&lt;/span&gt;
      }
    ]
  ]
}&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;编译结果如下：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/377ca82fb2e05cf9f73ad9f6f0bad35cc86b3e5749e33827ce6ddbc86282f74a/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313632363030363536303031362e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/377ca82fb2e05cf9f73ad9f6f0bad35cc86b3e5749e33827ce6ddbc86282f74a/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313632363030363536303031362e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1626006560016.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;false&lt;/code&gt; 还是进行了一个全量的引入。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://github.com/yaeSakuras/babel-demo/tree/master/package/polyfill1&quot;&gt;源码地址&lt;/a&gt;&lt;/p&gt;
&lt;h2 dir=&quot;auto&quot;&gt;polyfill 的第二种方式&lt;/h2&gt;
&lt;p dir=&quot;auto&quot;&gt;引入了 corejs、regenerator-runtime 这样的 polyfill 会有一定的副作用，比如：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;引入了新的全局对象：比如 Promise、WeakMap 等。&lt;/li&gt;
&lt;li&gt;修改现有的全局对象：比如修改了 Array、String 的原型链等。(如第一种方式的截图中)&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir=&quot;auto&quot;&gt;在应用开发中，上述行为问题不大，基本可控。但如果在库、工具的开发中引入 polyfill，则会带来潜在的问题。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;举个例子，我在项目中定义了跟规范不一致的 &lt;code class=&quot;notranslate&quot;&gt;Array.from()&lt;/code&gt; 函数，同时引入了一个库（注入了 polyfill），此时，这个库可能覆盖了自定义的 &lt;code class=&quot;notranslate&quot;&gt;Array.from()&lt;/code&gt; 函数，导致出错。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;那么接下来就是 &lt;code class=&quot;notranslate&quot;&gt;@babel/plugin-transform-runtime&lt;/code&gt; 的出场机会了。它将开发者依赖的全局内置对象等，抽取成单独的模块，并通过模块导入的方式引入，避免了对全局作用域的修改（污染）。&lt;a href=&quot;https://babeljs.io/docs/en/babel-plugin-transform-runtime&quot; rel=&quot;nofollow&quot;&gt;官方文档&lt;/a&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;strong&gt;runtime 这里简单介绍一下&lt;/strong&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;babel 的 runtime，包含两个部分。 &lt;code class=&quot;notranslate&quot;&gt;@babel/runtime&lt;/code&gt;、&lt;code class=&quot;notranslate&quot;&gt;@babel/plugin-transform-runtime&lt;/code&gt;。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;@babel/runtime&lt;/code&gt;：它其实是一个 babel 内部的库，使用在生产环境的 dependency，在 transform-runtime 作用的过程中，都会使用 &lt;code class=&quot;notranslate&quot;&gt;@babel/runtime&lt;/code&gt; 内部的模块，来代替重复的 helper 函数、对全局空间有污染的 core-js 和 regenerator-runtime 相关变量。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;code class=&quot;notranslate&quot;&gt;@babel/plugin-transform-runtime&lt;/code&gt;：这个插件主要有两个方面的用途。&lt;/p&gt;
&lt;ol dir=&quot;auto&quot;&gt;
&lt;li&gt;
&lt;p dir=&quot;auto&quot;&gt;babel 在转码过程中，会加入很多 babe l自己的 helper 函数，这些 helper 函数，在每个文件里可能都会重复存在，transform-runtime 插件可以把这些重复的 helper 函数，转换成公共的、单独的依赖引入，从而节省转码后的文件大小。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p dir=&quot;auto&quot;&gt;transform-runtime 可以帮助这种项目创建一个沙盒环境，即使在代码里用到了新的 ES 特性，它能将这些特性对应的全局变量，转换为对 core-js 和 regenerator-runtime 非全局变量版本的引用。这其实也应该看作是一种给代码提供 polyfill 的方式。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=&quot;auto&quot;&gt;接下来进入我们熟悉的实践环节。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;安装开发环境：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-shell&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;yarn add @babel/runtime @babel/runtime-corejs3
yarn add @babel/plugin-transform-runtime --save-dev&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;注意 @babel/runtime 要做为项目的 dependencies&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;auto&quot;&gt;然后修改我们的 babel 配置文件：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-json&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;{
  &lt;span class=&quot;pl-ent&quot;&gt;&quot;presets&quot;&lt;/span&gt;: [
    [
      &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@babel/preset-env&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    ]
  ],
  &lt;span class=&quot;pl-ent&quot;&gt;&quot;plugins&quot;&lt;/span&gt;: [
    [
      &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@babel/plugin-transform-runtime&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
      {
        &lt;span class=&quot;pl-ent&quot;&gt;&quot;corejs&quot;&lt;/span&gt;: {
          &lt;span class=&quot;pl-ent&quot;&gt;&quot;version&quot;&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;3&lt;/span&gt;,
          &lt;span class=&quot;pl-ent&quot;&gt;&quot;proposals&quot;&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;true&lt;/span&gt;
        }
      }
    ]
  ]
}&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;编译运行：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/ed0c5aa1ebc765ea2eda89ab2d26db662053b3bb32bb4a74b6ccb8ead2296880/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313632363030353931383132392e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/ed0c5aa1ebc765ea2eda89ab2d26db662053b3bb32bb4a74b6ccb8ead2296880/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313632363030353931383132392e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1626005918129.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;与第一种方式的 polyfill 对比可以发现，runtime 将新的 API 进行了重命名，它是不会重写覆盖原生方法的。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;需要注意 &lt;code class=&quot;notranslate&quot;&gt;@babel/plugin-transform-runtime&lt;/code&gt; 的默认配置中，是不会注入对提案的 polyfill 代码。如果想要支持提案中的 API，只需要增加和 @babel/preset-env 类似的配置项。&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-json&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;&lt;span class=&quot;pl-ent&quot;&gt;&quot;corejs&quot;&lt;/span&gt;: {
    &lt;span class=&quot;pl-ent&quot;&gt;&quot;version&quot;&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;3&lt;/span&gt;,
    &lt;span class=&quot;pl-ent&quot;&gt;&quot;proposals&quot;&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;true&lt;/span&gt;
}&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a href=&quot;https://github.com/yaeSakuras/babel-demo/tree/master/package/polyfill2&quot;&gt;源码地址&lt;/a&gt;&lt;/p&gt;
&lt;h1 dir=&quot;auto&quot;&gt;七、小结&lt;/h1&gt;
&lt;p dir=&quot;auto&quot;&gt;这里可能有人好奇，如果我们 &lt;code class=&quot;notranslate&quot;&gt;@babel/plugin-transform-runtime&lt;/code&gt; 开启 corejs 并且 &lt;code class=&quot;notranslate&quot;&gt;@babel/preset-env&lt;/code&gt; 也开启 &lt;code class=&quot;notranslate&quot;&gt;useBuiltIns&lt;/code&gt; 会怎么样。&lt;br&gt;
结论是：被使用到的 API polyfill 将会采用 runtime 的不污染全局方案（注意：@babel/preset-env targets 设置将会失效），而不被使用到的将会采用污染全局的。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;对于 &lt;code class=&quot;notranslate&quot;&gt;@babel/preset-env&lt;/code&gt; 我们可以设置 &lt;code class=&quot;notranslate&quot;&gt;debug&lt;/code&gt; 参数，来查看那些 API 被 polyfill，配置如下：&lt;/p&gt;
&lt;div class=&quot;highlight highlight-source-json&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;{
  &lt;span class=&quot;pl-ent&quot;&gt;&quot;presets&quot;&lt;/span&gt;: [
    [
      &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@babel/env&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
      {
      	&lt;span class=&quot;pl-ent&quot;&gt;&quot;debug&quot;&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;true&lt;/span&gt;,
        &lt;span class=&quot;pl-ent&quot;&gt;&quot;useBuiltIns&quot;&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;usage&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
        &lt;span class=&quot;pl-ent&quot;&gt;&quot;corejs&quot;&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;3&lt;/span&gt;
      }
    ]
  ]
}&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;效果如下：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer nofollow&quot; href=&quot;https://camo.githubusercontent.com/b4393e4c4845127c2d8d13b7c830296bdc73f1182b9cb05ee4da5ec5d8612c55/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313632363030393031333531342e706e67&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/b4393e4c4845127c2d8d13b7c830296bdc73f1182b9cb05ee4da5ec5d8612c55/68747470733a2f2f696d672e7a686f757a682e746563682f696d616765732f696d6167652d313632363030393031333531342e706e67&quot; alt=&quot;&quot; data-canonical-src=&quot;https://img.zhouzh.tech/images/image-1626009013514.png&quot; style=&quot;max-width: 100%;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;对于 polyfill 的使用场景：&lt;/p&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;如果是业务项目开：&lt;code class=&quot;notranslate&quot;&gt;@babel/plugin-transform-runtime&lt;/code&gt; ，建议关闭 corejs，polyfill 的引入由 &lt;code class=&quot;notranslate&quot;&gt;@babel/preset-env&lt;/code&gt; 完成，即开启 &lt;code class=&quot;notranslate&quot;&gt;useBuiltIns&lt;/code&gt;（如需其他配置，自行根据诉求配置）。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight highlight-source-json&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;{
  &lt;span class=&quot;pl-ent&quot;&gt;&quot;presets&quot;&lt;/span&gt;: [
    [
      &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@babel/preset-env&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
      {
        &lt;span class=&quot;pl-ent&quot;&gt;&quot;targets&quot;&lt;/span&gt;: {
          &lt;span class=&quot;pl-ent&quot;&gt;&quot;chrome&quot;&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;58&lt;/span&gt;
        },
        &lt;span class=&quot;pl-ent&quot;&gt;&quot;useBuiltIns&quot;&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;usage&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
        &lt;span class=&quot;pl-ent&quot;&gt;&quot;corejs&quot;&lt;/span&gt;: {
          &lt;span class=&quot;pl-ent&quot;&gt;&quot;version&quot;&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;3&lt;/span&gt;,
          &lt;span class=&quot;pl-ent&quot;&gt;&quot;proposals&quot;&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;true&lt;/span&gt;
        }
      }
    ]
  ],
  &lt;span class=&quot;pl-ent&quot;&gt;&quot;plugins&quot;&lt;/span&gt;: [
    [
      &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@babel/plugin-transform-runtime&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    ]
  ]
}&lt;/pre&gt;&lt;/div&gt;
&lt;ul dir=&quot;auto&quot;&gt;
&lt;li&gt;如果是 Library 开发：&lt;code class=&quot;notranslate&quot;&gt;@babel/plugin-transform-runtime&lt;/code&gt; ，建议开启 corejs，polyfill 由 &lt;code class=&quot;notranslate&quot;&gt;@babel/plugin-transform-runtime&lt;/code&gt; 引入。 &lt;code class=&quot;notranslate&quot;&gt;@babel/preset-env&lt;/code&gt; 关闭 &lt;code class=&quot;notranslate&quot;&gt;useBuiltIns&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight highlight-source-json&quot; dir=&quot;auto&quot;&gt;&lt;pre class=&quot;notranslate&quot;&gt;{
  &lt;span class=&quot;pl-ent&quot;&gt;&quot;presets&quot;&lt;/span&gt;: [
    [
      &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@babel/preset-env&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
    ]
  ],
  &lt;span class=&quot;pl-ent&quot;&gt;&quot;plugins&quot;&lt;/span&gt;: [
    [
      &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;@babel/plugin-transform-runtime&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,
      {
        &lt;span class=&quot;pl-ent&quot;&gt;&quot;corejs&quot;&lt;/span&gt;: {
          &lt;span class=&quot;pl-ent&quot;&gt;&quot;version&quot;&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;3&lt;/span&gt;,
          &lt;span class=&quot;pl-ent&quot;&gt;&quot;proposals&quot;&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot;&gt;true&lt;/span&gt;
        }
      }
    ]
  ]
}&lt;/pre&gt;&lt;/div&gt;
&lt;p dir=&quot;auto&quot;&gt;可能这里又有新的困惑：&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;为什么 &lt;code class=&quot;notranslate&quot;&gt;@babel/preset-env&lt;/code&gt; 不能使用不污染全局的 polyfill。（不污染全局的 polyfill 必须由 &lt;code class=&quot;notranslate&quot;&gt;@babel/plugin-transform-runtime&lt;/code&gt; 引入）&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;为什么要使用不污染全局的 polyfill 就必须要使用 &lt;code class=&quot;notranslate&quot;&gt;@babel/plugin-transform-runtime&lt;/code&gt;，而与此同时我必须妥协掉 &lt;code class=&quot;notranslate&quot;&gt;@babel/preset-env&lt;/code&gt; &lt;code class=&quot;notranslate&quot;&gt;targets&lt;/code&gt; 带来的体积优势。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;没有解决方案？&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;抱歉在现有的 babel 体系下还真的没有好办法来解决这个问题，当然 babel 也意识到了这个问题，于是有了 &lt;a href=&quot;https://github.com/babel/babel-polyfills&quot;&gt;babel-polyfills&lt;/a&gt;（不是 @babel/polyfills）这里不在详细展开，有兴趣的可以自行查看。&lt;/p&gt;
&lt;p dir=&quot;auto&quot;&gt;对没错，我们还遗漏了 react 工程中如何 polyfill。🙂&lt;/p&gt;</content>
</entry>
</feed>
