<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>React.js on Last Stand</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/</link><description>Recent content in React.js on Last Stand</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Wed, 16 Jul 2025 00:00:00 +0800</lastBuildDate><atom:link href="https://amatsuzero.github.io/LastStand/posts/frontend/react/index.xml" rel="self" type="application/rss+xml"/><item><title>JSX</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/jsx/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/jsx/</guid><description>&lt;p&gt;时下虽然接入 &lt;code&gt;JSX&lt;/code&gt; 语法的框架越来越多，但与之缘分最深的毫无疑问仍然是 &lt;code&gt;React&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;2013 年，当 &lt;code&gt;React&lt;/code&gt; 带着 &lt;code&gt;JSX&lt;/code&gt; 横空出世时，社区曾对 &lt;code&gt;JSX&lt;/code&gt; 有过不少的争议，但如今，越来越多的人面对 &lt;code&gt;JSX&lt;/code&gt; 都要说上一句“真香”！我们就来一起认识下这个“真香”的 &lt;code&gt;JSX&lt;/code&gt;，聊一聊“&lt;code&gt;JSX&lt;/code&gt; 代码是如何‘摇身一变’成为 &lt;code&gt;DOM&lt;/code&gt; 的”。&lt;/p&gt;
&lt;p&gt;开始之前请先思考几个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;JSX&lt;/code&gt; 的本质是什么，它和 JS 之间到底是什么关系？&lt;/li&gt;
&lt;li&gt;为什么要用 &lt;code&gt;JSX&lt;/code&gt;？不用会有什么后果？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;JSX&lt;/code&gt; 背后的功能模块是什么，这个功能模块都做了哪些事情？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;面对以上问题，如果无法形成清晰且系统的思路，那么很可能是把 &lt;code&gt;JSX&lt;/code&gt; 想得过于简单了。大多数人只是简单地把它理解为模板语法的一种，但事实上，&lt;code&gt;JSX&lt;/code&gt; 作为 &lt;code&gt;React&lt;/code&gt; 框架的一大特色，它与 &lt;code&gt;React&lt;/code&gt; 本身的运作机制之间存在着千丝万缕的联系，上述 3 个问题的答案，就恰恰隐藏在这层“联系”中。&lt;/p&gt;
&lt;h2 id="jsx-的本质javascript-的语法扩展"&gt;JSX 的本质：JavaScript 的语法扩展&lt;/h2&gt;
&lt;p&gt;JSX 到底是什么?看看 React 官网给出的一段定义：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;JSX&lt;/code&gt; 是 &lt;code&gt;JavaScript&lt;/code&gt; 的一种语法扩展，它和模板语言很接近，但是它充分具备 &lt;code&gt;JavaScript&lt;/code&gt; 的能力。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;“语法扩展”这一点在理解上几乎不会产生歧义，不过“它充分具备 &lt;code&gt;JavaScript&lt;/code&gt; 的能力”这句，却总让人摸不着头脑，&lt;code&gt;JSX&lt;/code&gt; 和 &lt;code&gt;JS&lt;/code&gt; 怎么看也不像是“一路人”啊？这就引出了“&lt;code&gt;JSX&lt;/code&gt; 语法是如何在 &lt;code&gt;JavaScript&lt;/code&gt; 中生效的”这个问题。&lt;/p&gt;
&lt;h3 id="jsx-语法是如何在-javascript-中生效的认识-babel"&gt;JSX 语法是如何在 JavaScript 中生效的：认识 Babel&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Facebook&lt;/code&gt; 公司给 &lt;code&gt;JSX&lt;/code&gt; 的定位是 &lt;code&gt;JavaScript&lt;/code&gt; 的“扩展”，而非 &lt;code&gt;JavaScript&lt;/code&gt; 的“某个版本”，这就直接决定了浏览器并不会像天然支持 &lt;code&gt;JavaScript&lt;/code&gt; 一样地支持 &lt;code&gt;JSX&lt;/code&gt;。那么，&lt;code&gt;JSX&lt;/code&gt; 的语法是如何在 &lt;code&gt;JavaScript&lt;/code&gt; 中生效的呢？&lt;code&gt;React&lt;/code&gt; 官网其实早已给过我们线索：&lt;/p&gt;</description></item><item><title>元素、组件、实例和节点</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-002/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-002/</guid><description>&lt;p&gt;React 中的元素、组件、实例和节点，是React中关系密切的4个概念，也是很容易让React 初学者迷惑的4个概念。现在，老干部就来详细地介绍这4个概念，以及它们之间的联系和区别，满足喜欢咬文嚼字、刨根问底的同学（老干部就是其中一员）的好奇心。&lt;/p&gt;
&lt;h4 id="元素-element"&gt;元素 (Element)&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;React 元素其实就是一个简单JavaScript对象，一个React 元素和界面上的一部分DOM对应，描述了这部分DOM的结构及渲染效果&lt;/strong&gt;。一般我们通过JSX语法创建React 元素，例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;element&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;h1&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;greeting&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Hello&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;world&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/h1&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;element是一个React 元素。在编译环节，JSX 语法会被编译成对React.createElement()的调用，从这个函数名上也可以看出，JSX语法返回的是一个React 元素。上面的例子编译后的结果为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;element&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;createElement&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;h1&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;greeting&amp;#39;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Hello, world!&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最终，element的值是类似下面的一个简单JavaScript对象：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;element&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;h1&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;greeting&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;children&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Hello, world&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;React 元素可以分为两类：DOM类型的元素和组件类型的元素。DOM类型的元素使用像h1、div、p等DOM节点创建React 元素，前面的例子就是一个DOM类型的元素；组件类型的元素使用React 组件创建React 元素，例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;buttonElement&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;color&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;red&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;OK&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/Button&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;buttonElement就是一个组件类型的元素，它的值是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;buttonElement&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Button&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;color&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;red&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;children&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;OK&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对于DOM类型的元素，因为和页面的DOM节点直接对应，所以React知道如何进行渲染。但是对于组件类型的元素，如buttonElement，React是无法直接知道应该把buttonElement渲染成哪种结构的页面DOM，这时就需要组件自身提供React能够识别的DOM节点信息，具体实现方式在介绍组件时会详细介绍。&lt;/p&gt;
&lt;p&gt;有了React 元素，我们应该如何使用它呢？其实，绝大多数情况下，我们都不会直接使用React 元素，React 内部会自动根据React 元素，渲染出最终的页面DOM。更确切地说，React元素描述的是React虚拟DOM的结构，React会根据虚拟DOM渲染出页面的真实DOM。&lt;/p&gt;
&lt;h4 id="组件-component"&gt;组件 (Component)&lt;/h4&gt;
&lt;p&gt;React 组件，应该是大家最熟悉的React中的概念。React通过组件的思想，将界面拆分成一个个可以复用的模块，每一个模块就是一个React 组件。一个React 应用由若干组件组合而成，一个复杂组件也可以由若干简单组件组合而成。&lt;/p&gt;
&lt;p&gt;React组件和React元素关系密切，&lt;strong&gt;React组件最核心的作用是返回React元素&lt;/strong&gt;。这里你也许会有疑问：React元素不应该是由React.createElement() 返回的吗？但React.createElement()的调用本身也是需要有“人”负责的，React组件正是这个“责任人”。React组件负责调用React.createElement()，返回React元素，供React内部将其渲染成最终的页面DOM。&lt;/p&gt;
&lt;p&gt;既然组件的核心作用是返回React元素，那么最简单的组件就是一个返回React元素的函数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Welcome&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;h1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Hello&lt;/span&gt;, {&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;}&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/h1&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Welcome是一个用函数定义的组件。如果使用类（class）定义组件，返回React元素的工作具体就由组件的render方法承担，例如：&lt;/p&gt;</description></item><item><title>state 与 props</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-003/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-003/</guid><description>&lt;h2 id="state"&gt;state&lt;/h2&gt;
&lt;h3 id="基本定义"&gt;基本定义&lt;/h3&gt;
&lt;p&gt;state是组件内部的状态（数据），不能够直接修改，必须要通过setState来改变值的状态，从而达到更新组件内部数据的作用。&lt;/p&gt;
&lt;h2 id="props"&gt;props&lt;/h2&gt;
&lt;h3 id="基本定义-1"&gt;基本定义&lt;/h3&gt;
&lt;p&gt;props是指组件间传递的一种方式，props自然也可以传递state。由于React的数据流是自上而下的，所以是从父组件向子组件进行传递；另外组件内部的this.props属性是只读的不可修改。&lt;/p&gt;
&lt;h2 id="代码示例"&gt;代码示例&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 父组件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stateJj&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;./stateJj.js&amp;#39;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 引入子组件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stateJjFather&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Component&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置state的默认值 且只能在constructor中设置
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mes&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;给子组件的信息&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fun&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; {&lt;span style="color:#a6e22e"&gt;mes&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;} &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 不写箭头函数 this指向会发生错误 也可以使用bind的方式绑定this
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;stateJj&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#39;给子组件的信息&amp;#39;&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;name1&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;mes&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;fun&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{(&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;) =&amp;gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;fun&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;)} &lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;obj&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;arr&lt;/span&gt;} &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 子组件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stateJj&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Component&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 这里面就有父组件传的值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置 默认state
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;text&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;initialValue&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;placeholder&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ES6 类中函数必须手动绑定
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;handleChange&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;handleChange&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handleChange&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setState&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;text&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;mes&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 设置props值的类型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;stateJj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;propTypes&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;optionalArray&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PropTypes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;array&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;optionalBool&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PropTypes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;bool&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;optionalFunc&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PropTypes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;func&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;optionalNumber&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PropTypes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;number&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;optionalObject&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PropTypes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;object&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;optionalString&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PropTypes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;optionalSymbol&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PropTypes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;symbol&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 目前可以声明的所有变量类型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 设置默认的props值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;stateJj&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;defaultProps&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="props的特性"&gt;props的特性&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;只读性&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;props经常被用作渲染组件和初始化状态，当一个组件被实例化之后，它的props是只读的，不可改变的。如果props在渲染过程中可以被改变，会导致这个组件显示的形态变得不可预测。只有通过父组件重新渲染的方式才可以把新的props传入组件中。&lt;/p&gt;</description></item><item><title>React 生命周期</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-lifecycle/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-lifecycle/</guid><description>&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;React从v16.3的版本开始， 对生命周期的钩子进行了渐进式的调整，分别废弃和新增了一些生命周期的钩子函数，本文会从以下四点开始讲解：&lt;/p&gt;
&lt;ol&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;/ol&gt;
&lt;h2 id="新旧生命周期对比"&gt;新旧生命周期对比&lt;/h2&gt;
&lt;p&gt;一个完整的React组件生命周期会依次调用如下钩子：&lt;/p&gt;
&lt;h3 id="old-lifecycle"&gt;old lifecycle&lt;/h3&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-lifecycle/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;挂载&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;constructor&lt;/li&gt;
&lt;li&gt;componentWillMount&lt;/li&gt;
&lt;li&gt;render&lt;/li&gt;
&lt;li&gt;componentDidMount&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;更新&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;componentWillReceiveProps&lt;/li&gt;
&lt;li&gt;shouldComponentUpdate&lt;/li&gt;
&lt;li&gt;componentWillUpdate&lt;/li&gt;
&lt;li&gt;render&lt;/li&gt;
&lt;li&gt;componentDidUpdate&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;卸载&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;componentWillUnmount&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="new-lifecycle"&gt;new lifecycle&lt;/h3&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-lifecycle/image-02.webp"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;挂载&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;constructor&lt;/li&gt;
&lt;li&gt;getDerivedStateFromProps&lt;/li&gt;
&lt;li&gt;render&lt;/li&gt;
&lt;li&gt;componentDidMount&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;更新&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;getDerivedStateFromProps&lt;/li&gt;
&lt;li&gt;shouldComponentUpdate&lt;/li&gt;
&lt;li&gt;render&lt;/li&gt;
&lt;li&gt;getSnapshotBeforeUpdate&lt;/li&gt;
&lt;li&gt;componentDidUpdate&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;卸载&lt;br&gt;
&lt;ul&gt;
&lt;li&gt;componentWillUnmount&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从以上生命周期的对比，我们不难看出，React从v16.3开始废弃 &lt;code&gt;componentWillMount&lt;/code&gt; &lt;code&gt;componentWillReceiveProps&lt;/code&gt; &lt;code&gt;componentWillUpdate&lt;/code&gt; 三个钩子函数&lt;/p&gt;
&lt;h2 id="分析废弃原因"&gt;分析废弃原因&lt;/h2&gt;
&lt;p&gt;Facebook花了两年多的时间搞出了React Fiber, 因为在v15的版本，更新过程是同步的，往往一个主线程长时间被占用，会导致页面性能问题&lt;/p&gt;
&lt;p&gt;而 &lt;strong&gt;React Fiber的机制:&lt;/strong&gt; 利用浏览器 &lt;code&gt;requestIdleCallback&lt;/code&gt; 将可中断的任务进行分片处理，每一个小片的运行时间很短，这样唯一的线程就不会被独占&lt;/p&gt;
&lt;p&gt;需要详细了解可以点下面链接 &lt;a href="https://zhuanlan.zhihu.com/p/26027085"&gt;Morgan大佬 - 知乎&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;那么React Fiber会对生命周期带来什么影响吗？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因为React Fiber &lt;code&gt;Reconciliation&lt;/code&gt; 这个过程有可能暂停然后继续执行，所以挂载和更新之前的生命周期钩子就有可能不执行或者多次执行；&lt;/p&gt;
&lt;p&gt;目前React为这几个生命周期钩子提供了别名，分别是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UNSAFE_componentWillMount&lt;/li&gt;
&lt;li&gt;UNSAFE_componentWillReceiveProps&lt;/li&gt;
&lt;li&gt;UNSAFE_componentWillUpdate&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;React17将只提供别名，取个别名的目的就是恶心你，不让你使用。&lt;/p&gt;</description></item><item><title>react hooks</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-hooks/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-hooks/</guid><description>&lt;h2 id="一-前言"&gt;一 前言&lt;/h2&gt;
&lt;p&gt;React hooks是react16.8 以后，react新增的钩子API，目的是增加代码的可复用性，逻辑性，弥补无状态组件没有生命周期，没有数据管理状态state的缺陷。&lt;/p&gt;
&lt;p&gt;本章节将介绍目前 React 提供的所有 hooks ，介绍其功能类型和基本使用方法。&lt;/p&gt;
&lt;h3 id="11-技术背景"&gt;1.1 技术背景&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;react hooks 解决了什么问题？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;先设想一下，如果没有 Hooks，函数组件能够做的只是接受 Props、渲染 UI ，以及触发父组件传过来的事件。所有的处理逻辑都要在类组件中写，这样会使 class 类组件内部错综复杂，每一个类组件都有一套独特的状态，相互之间不能复用，即便是 React 之前出现过 mixin 等复用方式，但是伴随出 mixin 模式下隐式依赖，代码冲突覆盖等问题，也不能成为 React 的中流砥柱的逻辑复用方案。所以 React 放弃 mixin 这种方式。&lt;/p&gt;
&lt;p&gt;类组件是一种面向对象思想的体现，类组件之间的状态会随着功能增强而变得越来越臃肿，代码维护成本也比较高，而且不利于后期 tree shaking。所以有必要做出一套函数组件代替类组件的方案，于是 Hooks 也就理所当然的诞生了。&lt;/p&gt;
&lt;p&gt;所以 Hooks 出现本质上原因是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;让函数组件也能做类组件的事，有自己的状态，可以处理一些副作用，能获取 ref ，也能做数据缓存。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解决逻辑复用难的问题。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;放弃面向对象编程，拥抱函数式编程。&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;为什么要使用自定义 Hooks ？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;自定义 hooks 是在 React Hooks 基础上的一个拓展，可以根据业务需求制定满足业务需要的组合 hooks ，更注重的是逻辑单元。通过业务场景不同，到底需要React Hooks 做什么，怎么样把一段逻辑封装起来，做到复用，这是自定义 hooks 产生的初衷。&lt;/p&gt;
&lt;p&gt;自定义 hooks 也可以说是 React Hooks 聚合产物，其内部有一个或者多个 React Hooks 组成，用于解决一些复杂逻辑。&lt;/p&gt;</description></item><item><title>Context API</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/context-api/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/context-api/</guid><description>&lt;h2 id="先看看react官网对于context的介绍"&gt;先看看React官网对于Context的介绍&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Context 提供了一个无需为每层组件手动添加 props，就能在组件树间进行数据传递的方法。在一个典型的 React 应用中，数据是通过 props 属性自上而下（由父及子）进行传递的，但这种做法对于某些类型的属性而言是极其繁琐的（例如：地区偏好，UI 主题），这些属性是应用程序中许多组件都需要的。Context 提供了一种在组件之间共享此类值的方式，而不必显式地通过组件树的逐层传递 props。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;个人理解转成大白话：&lt;code&gt;Context&lt;/code&gt;提供了一个&lt;strong&gt;局部的全局作用域&lt;/strong&gt;，使用Context则无需再手动的逐层传递&lt;code&gt;props&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;本文主要介绍3种&lt;code&gt;Context&lt;/code&gt;的使用方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;React.createContext&lt;/code&gt;提供的&lt;code&gt;Provider&lt;/code&gt;和&lt;code&gt;Consumer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;函数组件：&lt;code&gt;React.createContext&lt;/code&gt;提供的&lt;code&gt;Provider&lt;/code&gt;和&lt;code&gt;useContext&lt;/code&gt;钩子&lt;/li&gt;
&lt;li&gt;Class组件：&lt;code&gt;React.createContext&lt;/code&gt;提供的&lt;code&gt;Provider&lt;/code&gt;和&lt;code&gt;class&lt;/code&gt;的&lt;code&gt;contextType&lt;/code&gt;属性&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="第一种reactcreatecontext提供的provider和consumer"&gt;第一种：React.createContext提供的Provider和Consumer&lt;/h3&gt;
&lt;p&gt;先写好使用&lt;code&gt;Context&lt;/code&gt;的基础环境条件，后续的代码都是基于此环境&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//创建一个文件，暂且命名为context.js，导出createContext()的返回值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;createContext&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;react&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createContext&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在根组件&lt;code&gt;App.jsx&lt;/code&gt;中，导入上面写的&lt;code&gt;context&lt;/code&gt;，并使用&lt;code&gt;context&lt;/code&gt;提供的&lt;code&gt;Provider&lt;/code&gt;组件进行包裹，圈定&lt;strong&gt;局部的全局作用域&lt;/strong&gt;，传值后可以提供给子组件进行消费&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当 Provider 的 value 值发生变化时，它内部的所有消费组件都会重新渲染。Provider 及其内部 consumer 组件都不受制于 shouldComponentUpdate 函数，因此当 consumer 组件在其祖先组件退出更新的情况下也能更新。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;, { &lt;span style="color:#a6e22e"&gt;createContext&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;react&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyContext&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;./context&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GeneralC&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;./GeneralC&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;FnC&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;./FnC&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ClassC&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;./ClassC&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;App&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//Provider组件接收一个value属性，此处传入一个带有name属性的对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MyContext&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Provider&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{{ &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`context&amp;#39;s value is string!`&lt;/span&gt; }}&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#75715e"&gt;/*这里写后面要进行包裹的子组件,此处先行导入后续需要消费context的3个组件*/&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;GeneralC&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;hr&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;FnC&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;hr&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ClassC&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/MyContext.Provider&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在&lt;code&gt;GeneralC&lt;/code&gt;组件中,导入&lt;code&gt;context&lt;/code&gt;,使用其提供的&lt;code&gt;Consumer&lt;/code&gt;组件来订阅&lt;code&gt;Context&lt;/code&gt;的变更,需要一个函数作为子元素,函数的第一个形参便是&lt;code&gt;Provider&lt;/code&gt;组件提供的&lt;code&gt;value&lt;/code&gt;值&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;, { &lt;span style="color:#a6e22e"&gt;useReducer&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;react&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyContext&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;./context&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GeneralC&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; () =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MyContext&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Consumer&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {(&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;第一种使用Context方式获取的值&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;：&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;JSON&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;stringify&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/MyContext.Consumer&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GeneralC&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;此时页面中应该出现json格式的value值&lt;/p&gt;</description></item><item><title>条件渲染的常见方法和注意事项</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-007/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-007/</guid><description>&lt;h2 id="条件渲染方式"&gt;条件渲染方式&lt;/h2&gt;
&lt;h3 id="1-if-语句"&gt;1. if 语句&lt;/h3&gt;
&lt;p&gt;先从 React 最基本的条件类型来看。如果有数据就显示组件，如果没有数据就不显示任何内容。&lt;code&gt;posts&lt;/code&gt; 为需要渲染的列表：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;App&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;posts&lt;/span&gt; } &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;usePosts&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;posts&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;      &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PostList&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;posts&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;posts&lt;/span&gt;} &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种形式会生效的原因就是我们会提前返回，如果满足条件（&lt;code&gt;posts&lt;/code&gt; 值不存在），就通过&lt;code&gt;return null&lt;/code&gt; 在组件中不显示任何内容。&lt;/p&gt;
&lt;p&gt;如果有多个要检查的条件时，也可以使用 &lt;code&gt;if&lt;/code&gt; 语句。例如，在显示数据之前检查加载和错误状态：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;App&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;isLoading&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;isError&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;posts&lt;/span&gt; } &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;usePosts&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;   
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;isLoading&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Loading&lt;/span&gt;...&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;isError&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;Error&lt;span style="color:#f92672"&gt;!&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;      &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PostList&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;posts&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;posts&lt;/span&gt;} &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里我们可以多次使用 &lt;code&gt;if&lt;/code&gt; 语句，不需要再使用 &lt;code&gt;else&lt;/code&gt; 或者 &lt;code&gt;if-eles&lt;/code&gt; 语句，这样就减少了需要编写的代码，并且可读性更强。&lt;/p&gt;
&lt;h3 id="2-三元运算符"&gt;2. 三元运算符&lt;/h3&gt;
&lt;p&gt;当我们想提前退出或者什么都不显示时，if 语句会很有用。但是，如果我们不想写一个与返回的 JSX 分开的条件，而是直接在其中写呢？那就可以使用三元表达式来编写条件。&lt;/p&gt;
&lt;p&gt;在 React 中，我们必须在 JSX 中包含表达式，而不是语句。这就是为什么我们在 JSX 中只能使用三元表达式，而不是 if 语句来编写条件。&lt;/p&gt;</description></item><item><title>列表和key</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-008/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-008/</guid><description>&lt;p&gt;当我们在 React 要渲染一个列表时，如果没有在每一个被渲染的元件加上 key 这个 prop，就会跳出 &lt;code&gt;Warning: Each child in a list should have a unique “key” prop.&lt;/code&gt; 这个错误讯息。直到开发者把 &lt;code&gt;key&lt;/code&gt; 加上后，这个警告讯息才会消失。为什么要加上 key? 以及 key 有什么原则需要遵守? 这是在开发 React 时需要有的重要概念，也是面试经常会问的基础题。&lt;/p&gt;
&lt;h2 id="为什么需要-key"&gt;为什么需要 key？&lt;/h2&gt;
&lt;p&gt;key 就像一个独特身份，让 React 可以去分辨哪些子元件被新增、 移除，或是修改。 (编按：若要进一步说明此概念，推荐在面试时画下 Dan Abramov 的这个系列推文&lt;a href="https://twitter.com/dan_abramov/status/1415279090446204929"&gt;例子&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-008/image-01.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;从上面的例子可以看到，当今天红黄蓝三个圈，变成红蓝黄；这会有两个可能性。可能性一第二个圈跟第三个圈的位置互换；可能性二是位置没互换，但第二个圈变蓝色、第三个圈变黄色。如果没有一个独特辨识的机制，我们会没办法知道，究竟是哪一个可能性。&lt;/p&gt;
&lt;p&gt;如果没办法有效辨识，将可能出现 bug。举例来说，假如今天的圈圈是有状态的，例如里面有勾选方块，然后第个二圈有被勾选。假如今天换颜色是因为第二个圈被交换到第三个位置，这时表示新一次的渲染时，第三个圈要是被勾选的。不过假如我们没有一个辨识机制，要是 React 误以为换颜色不是因为换位置，而是单纯的第二个圈换颜色，那么将会渲染出仍是第二个圈是被勾选的；那么这就会是一个 bug。&lt;/p&gt;
&lt;p&gt;然而，有了 key 这个辨识机制，React 就会知道在新的一次渲染时，原本的状态应该被保留在列表中的哪一个元件中。因此，React 之所以需要 key，正是因为 key 可以让 React 知道，哪些子元件被新增、 移除，或是修改。&lt;/p&gt;
&lt;p&gt;除此之外，看到下面这段 React 官方文件的例子 (编按：面试时也推荐直接举这例子)。原本有个列表，我们在最上方新增一个 &lt;code&gt;&amp;lt;li&amp;gt;Connecticut&amp;lt;/li&amp;gt;&lt;/code&gt; ，如果没有 key，对 React 来说将会是，Duke 变成 Connecticut、Villanova 变成 Duke，而最后新增一个 Villanova。换句话说，整个列表都改变了，所以 React 会打掉旧的，重建一个新的列表。当列表变大时，就会很消耗效能。&lt;/p&gt;</description></item><item><title>react 事件机制</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-009/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-009/</guid><description>&lt;h2 id="一-前言"&gt;一 前言&lt;/h2&gt;
&lt;p&gt;我们来一起探讨一下&lt;code&gt;React&lt;/code&gt;事件原理，这篇文章，我尽量用通俗简洁的方式，把&lt;code&gt;React&lt;/code&gt;事件系统讲的明明白白。&lt;/p&gt;
&lt;p&gt;我们讲的&lt;code&gt;react&lt;/code&gt;版本是&lt;code&gt;16.13.1&lt;/code&gt; , &lt;code&gt;v17&lt;/code&gt;之后&lt;code&gt;react&lt;/code&gt;对于事件系统会有相关的改版，文章后半部分会提及。&lt;/p&gt;
&lt;p&gt;老规矩，在正式讲解&lt;code&gt;react&lt;/code&gt;之前，我们先想想这几个问题(&lt;strong&gt;如果我是面试官，你会怎么回答?&lt;/strong&gt;)：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;我们写的事件是绑定在&lt;code&gt;dom&lt;/code&gt;上么，如果不是绑定在哪里？&lt;/li&gt;
&lt;li&gt;为什么我们的事件不能绑定给组件？&lt;/li&gt;
&lt;li&gt;为什么我们的事件手动绑定&lt;code&gt;this&lt;/code&gt;(不是箭头函数的情况)&lt;/li&gt;
&lt;li&gt;为什么不能用 &lt;code&gt;return false&lt;/code&gt; 来阻止事件的默认行为？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;react&lt;/code&gt;怎么通过&lt;code&gt;dom&lt;/code&gt;元素，找到与之对应的 &lt;code&gt;fiber&lt;/code&gt;对象的？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onClick&lt;/code&gt;是在冒泡阶段绑定的？ 那么&lt;code&gt;onClickCapture&lt;/code&gt;就是在事件捕获阶段绑定的吗？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-009/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="必要的知识概念"&gt;必要的知识概念&lt;/h2&gt;
&lt;p&gt;在弄清楚&lt;code&gt;react&lt;/code&gt;事件之前，有几个概念我们必须弄清楚，因为只有弄明白这几个概念，在事件触发阶段，我们才能更好的理解&lt;code&gt;react&lt;/code&gt;处理事件本质。&lt;/p&gt;
&lt;h3 id="我们写在jsx事件终将变成什么"&gt;我们写在JSX事件终将变成什么？&lt;/h3&gt;
&lt;p&gt;我们先写一段含有点击事件的&lt;code&gt;react JSX&lt;/code&gt;语法，看一下它最终会变成什么样子？&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Component&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handerClick&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;) =&amp;gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onClick&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{ &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;handerClick&lt;/span&gt; } &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;按钮点击&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/button&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;经过&lt;code&gt;babel&lt;/code&gt;转换成&lt;code&gt;React.createElement&lt;/code&gt;形式，如下：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-009/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;最终转成&lt;code&gt;fiber&lt;/code&gt;对象形式如下：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-009/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fiber&lt;/code&gt;对象上的&lt;code&gt;memoizedProps&lt;/code&gt; 和 &lt;code&gt;pendingProps&lt;/code&gt;保存了我们的事件。&lt;/p&gt;
&lt;h3 id="什么是合成事件"&gt;什么是合成事件？&lt;/h3&gt;
&lt;p&gt;通过上一步我们看到了，我们声明事件保存的位置。但是事件有没有被真正的注册呢？我们接下来看一下：&lt;/p&gt;
&lt;p&gt;我们看一下当前这个元素&lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;上有没有绑定这个事件监听器呢？&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-009/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;button上绑定的事件&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们可以看到 ，&lt;code&gt;button&lt;/code&gt;上绑定了两个事件，一个是&lt;code&gt;document&lt;/code&gt;上的事件监听器，另外一个是&lt;code&gt;button&lt;/code&gt;，但是事件处理函数&lt;code&gt;handle&lt;/code&gt;，并不是我们的&lt;code&gt;handerClick&lt;/code&gt;事件，而是&lt;code&gt;noop&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;noop&lt;/code&gt;是什么呢？我们接着来看。&lt;/p&gt;
&lt;p&gt;原来&lt;code&gt;noop&lt;/code&gt;就指向一个空函数。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-009/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;然后我们看&lt;code&gt;document&lt;/code&gt;绑定的事件&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-009/image-06.webp"&gt;&lt;/p&gt;
&lt;p&gt;可以看到&lt;code&gt;click&lt;/code&gt;事件被绑定在&lt;code&gt;document&lt;/code&gt;上了。&lt;/p&gt;
&lt;p&gt;接下来我们再搞搞事情😂😂😂，在&lt;code&gt;demo&lt;/code&gt;项目中加上一个&lt;code&gt;input&lt;/code&gt;输入框，并绑定一个&lt;code&gt;onChange&lt;/code&gt;事件。睁大眼睛看看接下来会发生什么？&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Index&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Component&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;componentDidMount&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handerClick&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;) =&amp;gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handerChange&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;) =&amp;gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{{ &lt;span style="color:#a6e22e"&gt;marginTop&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;50px&amp;#39;&lt;/span&gt; }} &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onClick&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{ &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;handerClick&lt;/span&gt; } &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;按钮点击&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/button&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;placeholder&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;请输入内容&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onChange&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{ &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;handerChange&lt;/span&gt; } &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;我们先看一下&lt;code&gt;input dom&lt;/code&gt;元素上绑定的事件&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>受控组件和非受控组件</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-010/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-010/</guid><description>&lt;p&gt;前端开发经常会涉及表单的处理，或者其他一些用于输入的组件，比如日历组件。&lt;/p&gt;
&lt;p&gt;涉及到输入，就绕不开受控模式和非受控模式的概念。&lt;/p&gt;
&lt;p&gt;什么是受控，什么是非受控呢？&lt;/p&gt;
&lt;p&gt;想一下，改变表单值只有两种情况：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-010/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;用户去改变 value 或者代码去改变 value。&lt;/p&gt;
&lt;p&gt;如果不能通过代码改表单值 value，那就是非受控，也就是不受我们控制。&lt;/p&gt;
&lt;p&gt;但是代码可以给表单设置初始值 defaultValue。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-010/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;代码设置表单的初始 value，但是能改变 value 的只有用户，代码通过监听 onChange 来拿到最新的值，或者通过 ref 拿到 dom 之后读取 value。&lt;/p&gt;
&lt;p&gt;这种就是非受控模式。&lt;/p&gt;
&lt;p&gt;反过来，代码可以改变表单的 value，就是受控模式。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-010/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;注意，value 和 defaultValue 不一样：&lt;/p&gt;
&lt;p&gt;defaultValue 会作为 value 的初始值，后面用户改变的是 value。&lt;/p&gt;
&lt;p&gt;而一旦你给 input 设置了 value，那用户就不能修改它了，可以输入触发 onChange 事件，但是表单的值不会变。&lt;/p&gt;
&lt;p&gt;用户输入之后在 onChange 事件里拿到输入，然后通过代码去设置 value。&lt;/p&gt;
&lt;p&gt;这就是受控模式。&lt;/p&gt;
&lt;p&gt;其实绝大多数情况下，非受控就可以了，因为我们只是要拿到用户的输入，不需要手动去修改表单值。&lt;/p&gt;
&lt;p&gt;但有的时候，你需要根据用户的输入做一些处理，然后设置为表单的值，这种就需要受控模式。&lt;/p&gt;
&lt;p&gt;或者你想同步表单的值到另一个地方的时候，类似 Form 组件，也可以用受控模式。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;value 由用户控制就是非受控模式，由代码控制就是受控模式&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;我们写代码试一下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-lua" data-lang="lua"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npx create&lt;span style="color:#f92672"&gt;-&lt;/span&gt;vite
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-010/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;创建 vite + react 的项目。&lt;/p&gt;
&lt;p&gt;去掉 main.tsx 的 index.css 和 StrictMode：&lt;/p&gt;</description></item><item><title>高阶组件</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-011/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-011/</guid><description>&lt;h2 id="一-前言"&gt;一 前言&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;React&lt;/code&gt;高阶组件(&lt;code&gt;HOC&lt;/code&gt;)，对于很多&lt;code&gt;react&lt;/code&gt;开发者来说并不陌生，它是灵活使用&lt;code&gt;react&lt;/code&gt;组件的一种技巧，高阶组件本身不是组件，它是一个参数为组件，返回值也是一个组件的函数。&lt;/p&gt;
&lt;p&gt;高阶作用用于&lt;strong&gt;强化组件，复用逻辑，提升渲染性能等&lt;/strong&gt;作用。高阶组件也并不是很难理解，其实接触过后还是蛮简单的，接下来将按照，&lt;strong&gt;高阶组件理解？&lt;/strong&gt;，&lt;strong&gt;高阶组件具体怎么使用？应用场景&lt;/strong&gt;， &lt;strong&gt;高阶组件实践(源码级别)&lt;/strong&gt; 为突破口，带大家详细了解一下高阶组件。&lt;/p&gt;
&lt;p&gt;我们带着问题去开始今天的讨论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 什么是高阶组件，它解决了什么问题？&lt;/li&gt;
&lt;li&gt;2 有几种高阶组件，它们优缺点是什么？&lt;/li&gt;
&lt;li&gt;3 如何写一个优秀高阶组件？&lt;/li&gt;
&lt;li&gt;4 &lt;code&gt;hoc&lt;/code&gt;怎么处理静态属性，跨层级&lt;code&gt;ref&lt;/code&gt;等问题？&lt;/li&gt;
&lt;li&gt;5 高阶组件怎么控制渲染，隔离渲染？&lt;/li&gt;
&lt;li&gt;6 高阶组件怎么监控原始组件的状态？&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;高阶组件（HOC）是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分，它是一种基于 React 的组合特性而形成的设计模式。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-011/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="二-全方位看高阶组件"&gt;二 全方位看高阶组件&lt;/h2&gt;
&lt;h2 id="1-几种包装强化组件的方式"&gt;1 几种包装强化组件的方式&lt;/h2&gt;
&lt;h3 id="-mixin模式"&gt;① mixin模式&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;原型图&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-011/image-02.webp"&gt;&lt;/p&gt;
&lt;h4 id="老版本的react-mixins"&gt;老版本的&lt;code&gt;react-mixins&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;在&lt;code&gt;react&lt;/code&gt;初期提供一种组合方法。通过&lt;code&gt;React.createClass&lt;/code&gt;,加入&lt;code&gt;mixins&lt;/code&gt;属性，具体用法和&lt;code&gt;vue&lt;/code&gt; 中&lt;code&gt;mixins&lt;/code&gt;相似。具体实现如下。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;customMixin&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;componentDidMount&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;( &lt;span style="color:#e6db74"&gt;&amp;#39;------componentDidMount------&amp;#39;&lt;/span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;say&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;APP&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;createClass&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mixins&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [ &lt;span style="color:#a6e22e"&gt;customMixin&lt;/span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;getInitialState&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;alien&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; } &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt; ,&lt;span style="color:#a6e22e"&gt;world&lt;/span&gt; , &lt;span style="color:#a6e22e"&gt;my&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;is&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; } &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种&lt;code&gt;mixins&lt;/code&gt;只能存在&lt;code&gt;createClass&lt;/code&gt;中，后来&lt;code&gt;React.createClass&lt;/code&gt;连同&lt;code&gt;mixins&lt;/code&gt;这种模式被废弃了。&lt;code&gt;mixins&lt;/code&gt;会带来一些负面的影响。&lt;/p&gt;</description></item><item><title>Fragment 和 Portals</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/fragment-portals/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/fragment-portals/</guid><description>&lt;h2 id="一portals"&gt;一、Portals&lt;/h2&gt;
&lt;p&gt;某些情况下，我们希望渲染的内容独立于父组件，甚至独立于当前挂在的DOM元素（默认都是挂载到id为root的DOM元素上的）&lt;/p&gt;
&lt;p&gt;Portal提供了一种将子节点渲染到存在于&lt;strong&gt;父组件以外的DOM节点&lt;/strong&gt;的优秀的方案：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-scss" data-lang="scss"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;ReactDOM&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;.createPortal&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;child&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; &lt;span style="color:#f92672"&gt;container&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第一个参数：是任何可渲染的React子元素，例如&lt;strong&gt;一个元素、字符串或fragment&lt;/strong&gt; 第二个参数：是一个DOM元素&lt;/p&gt;
&lt;p&gt;通常来讲，当你从组件的 render 方法返回一个元素时，该元素将被挂载到 DOM 节点中离其最近的父节点：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// React 挂载了一个新的 div，并且把子元素渲染其中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;children&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然而，有时候将子元素插入到 DOM 节点中的不同位置也是有好处的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// React 并没有创建一个新的 div。它只是把子元素渲染到 `domNode` 中。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// `domNode` 是一个可以在任何位置的有效 DOM 节点。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ReactDOM&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;createPortal&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;children&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;domNode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一个 portal 的典型用例是当父组件有 overflow: hidden 或 z-index 样式时，但你需要子组件能够在视觉上“跳出”其容器。&lt;strong&gt;例如，对话框、悬浮卡以及提示框&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="案例"&gt;案例&lt;/h3&gt;
&lt;p&gt;比如将h2挂在到id为zs的节点下&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;index.html&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;html&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lang=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;en&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;charset=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;utf-8&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;icon&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;%PUBLIC_URL%/favicon.ico&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;viewport&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;width=device-width, initial-scale=1&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;meta&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;theme-color&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;#000000&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;meta&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;content=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Web site created using create-react-app&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;apple-touch-icon&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;%PUBLIC_URL%/logo192.png&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;manifest&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;%PUBLIC_URL%/manifest.json&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;React App&lt;span style="color:#f92672"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;noscript&amp;gt;&lt;/span&gt;You need to enable JavaScript to run this app.&lt;span style="color:#f92672"&gt;&amp;lt;/noscript&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;root&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;zs&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;App.jsx&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>性能优化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-013/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-013/</guid><description>&lt;p&gt;本文篇幅较长，将从 &lt;strong&gt;编译阶段&lt;/strong&gt; -&amp;gt; &lt;strong&gt;路由阶段&lt;/strong&gt; -&amp;gt; &lt;strong&gt;渲染阶段&lt;/strong&gt; -&amp;gt; &lt;strong&gt;细节优化&lt;/strong&gt; -&amp;gt; &lt;strong&gt;状态管理&lt;/strong&gt; -&amp;gt; &lt;strong&gt;海量数据源，长列表渲染&lt;/strong&gt; 方向分别加以探讨。&lt;/p&gt;
&lt;h2 id="一-不能输在起跑线上优化babel配置webpack配置为项"&gt;一 不能输在起跑线上，优化babel配置,webpack配置为项&lt;/h2&gt;
&lt;h3 id="1-真实项目中痛点"&gt;1 真实项目中痛点&lt;/h3&gt;
&lt;p&gt;当我们用&lt;code&gt;create-react-app&lt;/code&gt;或者&lt;code&gt;webpack&lt;/code&gt;构建&lt;code&gt;react&lt;/code&gt;工程的时候，有没有想过一个问题，我们的配置能否让我们的项目更快的构建速度，更小的项目体积，更简洁清晰的项目结构。 随着我们的项目越做越大，项目依赖越来越多，项目结构越来越来复杂，项目体积就会越来越大，构建时间越来越长，久而久之就会成了一个又大又重的项目，所以说我们要学会适当的为项目‘减负’，让项目不能输在起跑线上。&lt;/p&gt;
&lt;h3 id="2-一个老项目"&gt;2 一个老项目&lt;/h3&gt;
&lt;p&gt;拿我们之前接触过的一个&lt;code&gt;react&lt;/code&gt;老项目为例。我们没有用&lt;code&gt;dva&lt;/code&gt;,&lt;code&gt;umi&lt;/code&gt;快速搭建react，而是用&lt;code&gt;react&lt;/code&gt;老版本脚手架构建的，这对这种老的&lt;code&gt;react&lt;/code&gt;项目，上述的问题都会存在，下面让我们一起来看看。&lt;/p&gt;
&lt;p&gt;我们首先看一下项目结构。 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-013/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;再看看构建时间。&lt;/p&gt;
&lt;p&gt;为了方便大家看构建时间，我简单写了一个&lt;code&gt;webpack，plugin&lt;/code&gt; &lt;code&gt;ConsolePlugin&lt;/code&gt; ,记录了&lt;code&gt;webpack&lt;/code&gt;在一次&lt;code&gt;compilation&lt;/code&gt;所用的时间。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;chalk&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;chalk&amp;#39;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;/* console 颜色 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;slog&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;single-line-log&amp;#39;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;/* 单行打印 console */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ConsolePlugin&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;apply&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;compiler&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Monitor file change 记录当前改动文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;compiler&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;hooks&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;watchRun&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;tap&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;ConsolePlugin&amp;#39;&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;watching&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;changeFiles&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;watching&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;watchFileSystem&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;watcher&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;mtimes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;file&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;changeFiles&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;chalk&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;green&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;当前改动文件：&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;file&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * before a new compilation is created. 开始 compilation 编译 。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;compiler&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;hooks&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;compile&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;tap&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;ConsolePlugin&amp;#39;&lt;/span&gt;,()=&amp;gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;beginCompile&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Executed when the compilation has completed. 一次 compilation 完成。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;compiler&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;hooks&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;done&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;tap&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;ConsolePlugin&amp;#39;&lt;/span&gt;,()=&amp;gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;timer&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;clearInterval&lt;/span&gt;( &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;timer&lt;/span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;endTime&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Date().&lt;span style="color:#a6e22e"&gt;getTime&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;endTime&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;starTime&lt;/span&gt;) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;chalk&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;yellow&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39; 编译完成&amp;#39;&lt;/span&gt;) )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;chalk&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;yellow&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;编译用时：&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;秒&amp;#39;&lt;/span&gt; ) )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;beginCompile&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lineSlog&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;slog&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;stdout&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;text&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;开始编译：&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* 记录开始时间 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;starTime&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Date().&lt;span style="color:#a6e22e"&gt;getTime&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;timer&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setInterval&lt;/span&gt;(()=&amp;gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;text&lt;/span&gt; &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;█&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;lineSlog&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;chalk&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;green&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;text&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;构建时间如下：&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>代码分割</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-014/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-014/</guid><description>&lt;h2 id="什么是代码分割"&gt;什么是代码分割&lt;/h2&gt;
&lt;p&gt;代码分割是一种将代码分割成多个小块的方式，然后按需加载或并行加载所需的块的技术。代码分割可以用于减少应用程序的初始加载时间或将代码切割成可按需加载的块，从而减少应用程序所需的总体代码量。&lt;/p&gt;
&lt;h2 id="为什么要使用代码分割"&gt;为什么要使用代码分割&lt;/h2&gt;
&lt;p&gt;在大型应用程序中，将所有代码放在一个文件中会导致应用程序加载时间过长，影响用户体验。为了解决这个问题，我们需要将代码分割成小块，然后按需加载或并行加载所需的块。&lt;/p&gt;
&lt;h2 id="代码分割的方式"&gt;代码分割的方式&lt;/h2&gt;
&lt;h3 id="1-动态导入-import"&gt;1. 动态导入 import&lt;/h3&gt;
&lt;p&gt;import()是 JavaScript 中的一个动态导入语法，它允许在运行时异步加载模块。它返回一个 Promise，该 Promise 在模块加载完成后被解析为一个包含导出内容的模块对象。 使用 import()的语法如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;modulePath&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;then&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;module&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 使用导入的模块
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 处理错误
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这个语法中，modulePath 是一个字符串，用于指定要加载的模块路径。它可以是相对路径或绝对路径，也可以是一个包名。 当调用 import(modulePath)时，它会返回一个 Promise。这个 Promise 会在模块加载完成后被解析为一个包含导出内容的模块对象。你可以使用.then()方法来处理解析后的模块对象，并在其中使用导入的模块。 如果模块加载失败，Promise 会被拒绝，并触发.catch()方法中的错误处理逻辑。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意事项 import()只能在模块的顶层作用域中使用，不能在函数内部或条件语句中使用。这是因为 import()是静态解析的，它在代码加载时就会执行，而不是在运行时。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;另外，import()可以与其他语法结合使用，例如动态模块路径和对象解构。 动态模块路径：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;modulePath&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;./myModule&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;modulePath&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;then&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;module&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 使用导入的模块
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 处理错误
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这个示例中，modulePath 是一个变量，它的值在运行时确定。这样可以根据需要动态加载不同的模块。&lt;/p&gt;
&lt;p&gt;对象解构：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;./myModule&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;then&lt;/span&gt;(({ &lt;span style="color:#a6e22e"&gt;myFunction&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;myVariable&lt;/span&gt; }) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 使用导入的函数和变量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;myFunction&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;myVariable&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 处理错误
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-reactlazy"&gt;2. React.lazy&lt;/h3&gt;
&lt;p&gt;React.lazy 是 React 16.6 版本引入的一个特性，它可以让你以动态的方式进行代码拆分（code splitting）。通过 React.lazy，你可以延迟加载（lazy load）一个组件，只有在需要时才会加载该组件，从而提高应用程序的性能。 React.lazy 的用法如下：&lt;/p&gt;</description></item><item><title>react 状态提升</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-015/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-015/</guid><description>&lt;p&gt;在开始介绍状态提升之前，我想先介绍一下 Prop Drilling（属性钻取）的概念。&lt;/p&gt;
&lt;h2 id="什么是prop-drilling-"&gt;什么是Prop Drilling ？&lt;/h2&gt;
&lt;p&gt;那么，什么是状态提升呢？我们都知道 React 中的&lt;strong&gt;prop drilling&lt;/strong&gt;（属性钻取）。&lt;strong&gt;prop drilling&lt;/strong&gt;意味着从父组件向子组件传递一些 props。通过这种方式，我们可以在不同的组件之间共享数据或函数。可以使用 prop 传递任何类型的数据。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-015/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;在上面的示例代码中，你可以看到，Home 组件具有一个名为 name 的状态，并且她与子组件共用 name 变量。在 React 中，只能将数据从父组件传递到子组件。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-015/image-02.webp"&gt;&lt;/p&gt;
&lt;h2 id="什么是-state-lifting"&gt;什么是 State Lifting&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-015/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;一般来说，状态提升允许你将数据从子组件移动到父组件，与Props Drilling不同，你可以在父组件使用子组件的状态值。这是不是很疯狂？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在 React 生态中，我们知道数据只能从父组件流向子组件，但现在将学习如何让数据反过来流动。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;但是，为什么要这么做？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们可以在父组件中定义状态并将其以 prop 的方式传递给子组件，但是这么做有可能会导致性能损失和代码复杂度提升。在我之前的博客中有提到：保持状态本地化很重要。因为当状态更新时，组件以及该组件的子组件都会重新渲染。&lt;/p&gt;
&lt;p&gt;此外对于代码复杂性，对于如 Modal 这样的组件，选择在子组件中声明状态而不是在父组件中声明状态，将能够使代码更易于阅读。使用这种方法，你不必在每个父组件中声明状态。&lt;/p&gt;
&lt;p&gt;通常对应用程序中的大多数组件来说，这是不必要的。但是，对于某些类型的组件，特别是可重用组件，会有这种需求。下面描述一下最通用的场景。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;多说无用，上代码：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-015/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;例如，我们有一个常见的 Modal 组件，我们想要在 Modal 中保留可见性状态。当一些组件想要使用这个 Modal 时，通常会定义自己的可见状态，但是通过 State Lifting，这个步骤将不再必要。&lt;/p&gt;
&lt;p&gt;在 上面的 Modal 组件中，做了如下操作：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;首先，使用forwardRef执行 ref 转发，ref 转发是一种自动将 ref 通过组件传递给子组件的技术。&lt;/li&gt;
&lt;li&gt;使用 useState 声明状态以控制Modal组件的展示或隐藏。&lt;/li&gt;
&lt;li&gt;使用 React 内置的 &lt;code&gt;useImperativeHandle&lt;/code&gt; hook 将属性或者方法暴露出去，这里我们添加了一些数据和函数供父组件使用。现在父组件可以直接调用子组件的&lt;code&gt;show&lt;/code&gt;、&lt;code&gt;hide&lt;/code&gt;、&lt;code&gt;isVisble&lt;/code&gt;这些方法和属性。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-015/image-05.webp"&gt;&lt;/p&gt;</description></item><item><title>forwardRef 该怎么用？</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-016/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-016/</guid><description>&lt;h2 id="reactforwardref"&gt;React.forwardRef&lt;/h2&gt;
&lt;p&gt;对于ref转发，官网是这样描述的&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ref 转发是一项将 &lt;a href="https://react.docschina.org/docs/refs-and-the-dom.html"&gt;ref&lt;/a&gt; 自动地通过组件传递到其一子组件的技巧。对于大多数应用中的组件来说，这通常不是必需的。但其对某些组件，尤其是可重用的组件库是很有用的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;想详细了解的可以去看官方文档 &lt;a href="https://react.docschina.org/docs/forwarding-refs.html#forwarding-refs-in-higher-order-components"&gt;Refs 转发 – React (docschina.org)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;现在让我们直奔主题吧！&lt;/p&gt;
&lt;p&gt;&lt;code&gt;React.forwardRef(render)&lt;/code&gt;的返回值是&lt;code&gt;react&lt;/code&gt;组件，接收的参数是一个 &lt;code&gt;render&lt;/code&gt;函数，函数签名为&lt;code&gt;render(props, ref)&lt;/code&gt;，第二个参数将其接受的 &lt;a href="https://react.docschina.org/docs/refs-and-the-dom.html"&gt;ref&lt;/a&gt; 属性&lt;strong&gt;转发&lt;/strong&gt;到&lt;code&gt;render&lt;/code&gt;返回的组件中。&lt;/p&gt;
&lt;p&gt;这项技术并不常见，但在以下两种场景中特别有用:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;转发 &lt;code&gt;ref&lt;/code&gt; 到组件内部的&lt;code&gt;DOM&lt;/code&gt; 节点上&lt;/li&gt;
&lt;li&gt;在高阶组件中转发&lt;code&gt;ref&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="转发-ref到组件内部的dom节点"&gt;转发 &lt;code&gt;ref&lt;/code&gt;到组件内部的&lt;code&gt;DOM&lt;/code&gt;节点&lt;/h2&gt;
&lt;p&gt;比如我们想要将一个组件内部的某个元素暴露出去, 就可以这么做&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// App.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;react&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Foo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;./component/Foo&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;App&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Component&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;createRef&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ↑5
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;handleClick&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;input&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;current&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 6
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;focus&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onClick&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;handleClick&lt;/span&gt;}&amp;gt;&lt;span style="color:#a6e22e"&gt;click&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#75715e"&gt;/*2*/&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;Foo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ref&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;}/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Foo.jsx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;react&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Foo&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;forwardRef&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;myRef&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;....&lt;span style="color:#a6e22e"&gt;一些其他节点&lt;/span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt; {&lt;span style="color:#75715e"&gt;/*4*/&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;defaultValue&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;ref 成功转发到 Foo 组件内部的 input节点上&amp;#39;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ref&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;myRef&lt;/span&gt;}/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;....&lt;span style="color:#a6e22e"&gt;一些其他节点&lt;/span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;....&lt;span style="color:#a6e22e"&gt;一些其他节点&lt;/span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Foo&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;仔细看代码中标记的数字，这是&lt;code&gt;ref&lt;/code&gt;转发的流程:&lt;/p&gt;</description></item><item><title>错误边界</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-017/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-017/</guid><description>&lt;p&gt;人无完人，代码总会出错，出错并不可怕，关键是怎么处理。&lt;/p&gt;
&lt;p&gt;我就想问问大家react的应用的错误怎么捕捉呢？ 这个时候：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;小白+++：怎么处理？&lt;/li&gt;
&lt;li&gt;小白++： ErrorBoundary&lt;/li&gt;
&lt;li&gt;小白+： ErrorBoundary, try catch&lt;/li&gt;
&lt;li&gt;小黑#: ErrorBoundary, try catch, window.onerror&lt;/li&gt;
&lt;li&gt;小黑##: 这个是个严肃的问题，我知道N种处理方式，你有什么更好的方案?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="errorboundary"&gt;ErrorBoundary&lt;/h2&gt;
&lt;p&gt;EerrorBoundary是16版本出来的，有人问那我的15版本呢，我不听我不听，反正我用16，当然15有&lt;code&gt;unstable_handleError&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;关于ErrorBoundary官网介绍比较详细，这个不是重点，重点是他能捕捉哪些异常。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;子组件的渲染&lt;/li&gt;
&lt;li&gt;生命周期函数&lt;/li&gt;
&lt;li&gt;构造函数&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ErrorBoundary&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Component&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;hasError&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;componentDidCatch&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;info&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Display fallback UI
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setState&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;hasError&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// You can also log the error to an error reporting service
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;logErrorToMyService&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;info&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;render&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;hasError&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// You can render any custom fallback UI
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;h1&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Something&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;went&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;wrong&lt;/span&gt;.&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/h1&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;children&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ErrorBoundary&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MyWidget&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/ErrorBoundary&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;开源世界就是好，早有大神封装了&lt;a href="https://www.npmjs.com/package/react-error-boundary"&gt;react-error-boundary&lt;/a&gt; 这种优秀的库。&lt;br&gt;
你只需要关心出现错误后需要关心什么，还以来个 &lt;code&gt;Reset&lt;/code&gt;, 完美。&lt;/p&gt;</description></item><item><title>react-router</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-router/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-router/</guid><description>&lt;p&gt;写在前面：为什么要学习react-router底层源码? 为什么要弄明白整个路由流程？&lt;/p&gt;
&lt;p&gt;学习react-router，有助于我们学习单页面应用(spa)路由跳转原理，让我们理解从&lt;code&gt;history.push&lt;/code&gt;，到组件页面切换的全套流程，使我们在面试的时候不再为路由相关的问题发怵，废话不说，让我们开启深入react-router源码之旅吧。&lt;/p&gt;
&lt;h2 id="一-正确理解react-router"&gt;一 正确理解react-router&lt;/h2&gt;
&lt;h3 id="1-理解单页面应用"&gt;1 理解单页面应用&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;什么是单页面应用？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;个人理解，单页面应用是使用一个html下，一次性加载js, css等资源，所有页面都在一个容器页面下，页面切换实质是组件的切换。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-router/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="2-react-router初探揭露路由原理面纱"&gt;2 react-router初探，揭露路由原理面纱&lt;/h3&gt;
&lt;h4 id="react-router-dom和react-router和history库三者什么关系"&gt;①&lt;code&gt;react-router-dom&lt;/code&gt;和&lt;code&gt;react-router&lt;/code&gt;和&lt;code&gt;history&lt;/code&gt;库三者什么关系&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;**history**&lt;/code&gt; 可以理解为&lt;code&gt;react-router&lt;/code&gt;的核心，也是整个路由原理的核心，里面集成了&lt;code&gt;popState,history.pushState&lt;/code&gt;等底层路由实现的原理方法，接下来我们会一一解释。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;**react-router**&lt;/code&gt;可以理解为是&lt;code&gt;**react-router-dom**&lt;/code&gt;的核心，里面封装了&lt;code&gt;Router，Route，Switch&lt;/code&gt;等核心组件,实现了从路由的改变到组件的更新的核心功能,在我们的项目中只要一次性引入&lt;code&gt;react-router-dom&lt;/code&gt;就可以了。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;**react-router-dom**&lt;/code&gt;,在&lt;code&gt;react-router&lt;/code&gt;的核心基础上，添加了用于跳转的&lt;code&gt;Link&lt;/code&gt;组件，和histoy模式下的&lt;code&gt;BrowserRouter&lt;/code&gt;和hash模式下的&lt;code&gt;HashRouter&lt;/code&gt;组件等。所谓&lt;code&gt;**BrowserRouter和HashRouter，也只不过用了history库中createBrowserHistory和createHashHistory方法**&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;react-router-dom&lt;/code&gt; 我们不多说了，这里我们重点看一下&lt;code&gt;react-router&lt;/code&gt;。&lt;/p&gt;
&lt;h4 id="来个小demo尝尝鲜"&gt;②来个小demo尝尝鲜?&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;BrowserRouter&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;as&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Router&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Switch&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Route&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Redirect&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;Link&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;react-router-dom&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Detail&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;../src/page/detail&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;List&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;../src/page/list&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Index&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;../src/page/home/index&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;menusList&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;首页&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/index&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;列表&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/list&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;详情&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/detail&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;index&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; () =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Router&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* link 路由跳转 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;menusList&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;map&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;router&lt;/span&gt;=&amp;gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;router&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;to&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{ &lt;span style="color:#a6e22e"&gt;router&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;path&lt;/span&gt; } &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;span&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;className&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;routerLink&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;router&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;}&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/span&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/Link&amp;gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Switch&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Route&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#39;/index&amp;#39;&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;component&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;Index&lt;/span&gt;} &lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/Route&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Route&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#39;/list&amp;#39;&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;component&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;List&lt;/span&gt;} &lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/Route&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Route&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#39;/detail&amp;#39;&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;component&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;Detail&lt;/span&gt;} &lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/Route&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#75715e"&gt;/* 路由不匹配，重定向到/index */&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Redirect&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/*&amp;#39;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/index&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/Switch&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/Router&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;效果如下&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>react 渲染机制</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-019/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-019/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;文本分为两大部分讲解，一部分是&lt;code&gt;首次挂载渲染&lt;/code&gt;原理，另一部分是&lt;code&gt;更新和卸载&lt;/code&gt;原理，很多地方非常抽象，希望大家仔细阅读，不然容易脱节。废话不多话，开车！！&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;在开始之前，需要一些前置知识才能帮助我们更好的理解整个渲染过程。首先就是&lt;code&gt;生命周期(16版本之后)&lt;/code&gt;，为什么要讲一下生命周期？跟渲染原理有关系吗？当然有，如果你不理解渲染原理的话，更新一个嵌套很深的组件你甚至连&lt;code&gt;父与子&lt;/code&gt;生命周期执行的先后顺序都不知道。本文直接对照&lt;code&gt;16&lt;/code&gt;版本之后的&lt;code&gt;新生命周期&lt;/code&gt;进行讲解，就不讲解老版本了。&lt;/p&gt;
&lt;h2 id="初探-生命周期"&gt;初探-生命周期&lt;/h2&gt;
&lt;p&gt;顾名思义，跟人生一样，&lt;code&gt;生命周期&lt;/code&gt;就是一个组件从&lt;code&gt;诞生&lt;/code&gt;到&lt;code&gt;销毁&lt;/code&gt;的过程。&lt;code&gt;React&lt;/code&gt;在组件的&lt;code&gt;生命周期&lt;/code&gt;中注册了一系列的&lt;code&gt;钩子函数&lt;/code&gt;，支持开发者在其中注入代码，并在适当的时机运行。这里指的&lt;code&gt;生命周期&lt;/code&gt;仅针对于&lt;code&gt;类组件&lt;/code&gt;中的&lt;code&gt;钩子函数&lt;/code&gt;。因为&lt;code&gt;生命周期&lt;/code&gt;不是本文的重点，所以&lt;code&gt;Hooks&lt;/code&gt;中的新增的&lt;code&gt;钩子函数&lt;/code&gt;在本文中均不涉及，可以以后出个&lt;code&gt;Hooks&lt;/code&gt;原理篇。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-019/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;从图中可以看到，我把&lt;code&gt;生命周期&lt;/code&gt;分为了&lt;code&gt;挂载阶段&lt;/code&gt;、&lt;code&gt;更新阶段&lt;/code&gt;、&lt;code&gt;卸载阶段&lt;/code&gt;三个阶段。同时，在&lt;code&gt;挂载阶段&lt;/code&gt;和&lt;code&gt;更新阶段&lt;/code&gt;都会运行&lt;code&gt;getDerivedStateFromProps&lt;/code&gt;和&lt;code&gt;render&lt;/code&gt;，卸载阶段很好理解，只有一个&lt;code&gt;componentWillUnMount&lt;/code&gt;，在卸载组件之前做一些事情，通常用来&lt;code&gt;清除定时器等副作用操作&lt;/code&gt;。那么&lt;code&gt;挂载阶段&lt;/code&gt;和&lt;code&gt;更新阶段&lt;/code&gt;中的生命周期我们来逐一看下每个运行点及作用。&lt;/p&gt;
&lt;h3 id="1-constructor"&gt;1. constructor&lt;/h3&gt;
&lt;p&gt;在同一个类组件对象只会运行一次。所以经常来做一些&lt;code&gt;初始化&lt;/code&gt;的操作。同一个组件对象被多次创建，它们的&lt;code&gt;construcotr&lt;/code&gt;互不干扰。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意：在&lt;code&gt;construcotr&lt;/code&gt;中要尽量避免（最好禁止）使用&lt;code&gt;setState&lt;/code&gt;。&lt;/strong&gt; 我们都知道使用&lt;code&gt;setState&lt;/code&gt;会造成页面的重新渲染，但是在&lt;code&gt;初始化&lt;/code&gt;阶段，页面都还没有将&lt;code&gt;真实DOM&lt;/code&gt;挂载到页面上，那么重新渲染的又有什么意义呢。除&lt;code&gt;异步&lt;/code&gt;的情况，比如&lt;code&gt;setInterval&lt;/code&gt;中使用&lt;code&gt;setState&lt;/code&gt;是没问题的，因为在执行的时候页面早已&lt;code&gt;渲染完成&lt;/code&gt;。但也最好不要，容易一些引起奇怪的问题。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;constructor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;num&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//不可以，直接Warning
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setState&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;num&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;num&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//可以使用，但不建议
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setInterval&lt;/span&gt;(()=&amp;gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setState&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;num&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;num&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/react/react-019/image-02.webp"&gt;&lt;/p&gt;
&lt;h3 id="2-静态属性-static-getderivedstatefromprops"&gt;2. 静态属性 static getDerivedStateFromProps&lt;/h3&gt;
&lt;p&gt;该方法是一个&lt;code&gt;静态属性&lt;/code&gt;，在&lt;code&gt;16&lt;/code&gt;版本之前不存在，在新版&lt;code&gt;生命周期&lt;/code&gt;中主要用来取代&lt;code&gt;componentWillMount&lt;/code&gt;和&lt;code&gt;componentWillReceiveProps&lt;/code&gt;，因为这两个&lt;code&gt;老生命周期&lt;/code&gt;方法在一些开发者不规范的使用下极容易产生一些&lt;code&gt;反模式&lt;/code&gt;的bug。因为是&lt;code&gt;静态方法&lt;/code&gt;，所以你在其中根本拿不到&lt;code&gt;this&lt;/code&gt;，更不可能调用&lt;code&gt;setState&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;该方法在&lt;code&gt;挂载阶段&lt;/code&gt;和&lt;code&gt;更新阶段&lt;/code&gt;都会运行。它有两个参数&lt;code&gt;props&lt;/code&gt;和&lt;code&gt;state&lt;/code&gt;当前的&lt;code&gt;属性值&lt;/code&gt;和&lt;code&gt;状态&lt;/code&gt;。它的返回值会合并掉当前的&lt;code&gt;状态（state）&lt;/code&gt;。 如果返回了非&lt;code&gt;Object&lt;/code&gt;的值，那么它啥都不会做，如果返回的是&lt;code&gt;Object&lt;/code&gt;，那么它将会跟当前的状态合并，可以理解为&lt;a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign"&gt;Object.assign&lt;/a&gt;。通常情况下，几乎不怎么使用该方法。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 静态方法，首次挂载和更新渲染都会运行该方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * @param {*} props 当前属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * @param {*} state 当前状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getDerivedStateFromProps&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;state&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// return 1; //没用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;num&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;999&lt;/span&gt;, &lt;span style="color:#75715e"&gt;//合并到当前state对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-render"&gt;3. &lt;code&gt;render&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;最重要的&lt;code&gt;生命周期&lt;/code&gt;，没有之一。用来生成&lt;code&gt;虚拟节点（vDom）&lt;/code&gt;树。该方法只要遇到需要重新渲染都会运行。同样的，在&lt;code&gt;render&lt;/code&gt;中也严禁使用&lt;code&gt;setState&lt;/code&gt;，因为会导致无限&lt;code&gt;递归&lt;/code&gt;重新渲染导致&lt;code&gt;爆栈&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>React函数组件更新</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-020/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-020/</guid><description>&lt;p&gt;React的函数组件（Function Components）自Hooks推出以来已成为React开发的主流方式。理解函数组件的更新原理对于编写高效、可维护的React应用至关重要。本文将深入探讨React函数组件的更新机制。&lt;/p&gt;
&lt;h2 id="一函数组件与类组件的本质区别"&gt;一、函数组件与类组件的本质区别&lt;/h2&gt;
&lt;p&gt;在深入更新原理前，我们需要明确函数组件与类组件的根本区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;类组件&lt;/strong&gt;：是类的实例，拥有实例属性和生命周期方法&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;函数组件&lt;/strong&gt;：是纯函数，接收props作为参数，返回JSX&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这种本质区别决定了它们的更新行为完全不同。&lt;/p&gt;
&lt;h2 id="二函数组件的执行机制"&gt;二、函数组件的执行机制&lt;/h2&gt;
&lt;p&gt;当React需要渲染一个函数组件时，它只是简单地&lt;strong&gt;调用这个函数&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyComponent&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;{&lt;span style="color:#a6e22e"&gt;props&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;message&lt;/span&gt;}&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// React内部大致这样处理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;element&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyComponent&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;message&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Hello&amp;#39;&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每次渲染都是&lt;strong&gt;全新的函数调用&lt;/strong&gt;，所有局部变量和函数都会重新创建。这与类组件形成鲜明对比，类组件在更新时会复用同一个实例。&lt;/p&gt;
&lt;h2 id="三触发更新的场景"&gt;三、触发更新的场景&lt;/h2&gt;
&lt;p&gt;函数组件的更新主要由以下情况触发：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;父组件重新渲染&lt;/strong&gt;：即使props未变化，父组件渲染也会导致子组件重新渲染&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;props发生变化&lt;/strong&gt;：当传入组件的props值改变时&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;状态更新&lt;/strong&gt;：通过useState、useReducer等Hook更新状态&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;context变化&lt;/strong&gt;：组件订阅的context值发生变化&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hooks依赖变化&lt;/strong&gt;：useEffect、useMemo等Hook的依赖项发生变化&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="四react的渲染流程"&gt;四、React的渲染流程&lt;/h2&gt;
&lt;p&gt;函数组件的更新遵循React的渲染流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;触发更新&lt;/strong&gt;：通过setState、父组件渲染等途径触发更新&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;协调阶段（Reconciliation）&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;React调用函数组件获取新的JSX&lt;/li&gt;
&lt;li&gt;与上一次渲染的JSX进行对比（Virtual DOM Diff）&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;提交阶段（Commit）&lt;/strong&gt;：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;将差异应用到真实DOM&lt;/li&gt;
&lt;li&gt;执行useLayoutEffect的回调&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;strong&gt;浏览器绘制&lt;/strong&gt;：浏览器重绘屏幕&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;副作用执行&lt;/strong&gt;：执行useEffect的回调&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="五hooks与组件更新"&gt;五、Hooks与组件更新&lt;/h2&gt;
&lt;p&gt;Hooks是函数组件能够拥有状态和生命周期的关键。理解Hooks的工作机制对理解组件更新至关重要。&lt;/p&gt;
&lt;h3 id="usestate的工作原理"&gt;useState的工作原理&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; [&lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;setCount&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;useState&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;React会在组件首次渲染时为每个useState调用分配一个&amp;quot;状态单元&amp;quot;&lt;/li&gt;
&lt;li&gt;后续更新时，React会按照Hooks的调用顺序来提供对应的状态值&lt;/li&gt;
&lt;li&gt;setCount调用会触发组件的重新渲染&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="useeffect与更新"&gt;useEffect与更新&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;useEffect&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 副作用代码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; () =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 清理函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, [&lt;span style="color:#a6e22e"&gt;dependencies&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;组件每次渲染后，React会比较依赖项数组&lt;/li&gt;
&lt;li&gt;如果依赖项变化或没有提供依赖项数组，副作用会重新执行&lt;/li&gt;
&lt;li&gt;清理函数会在副作用重新执行前或组件卸载时执行&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="六优化更新性能"&gt;六、优化更新性能&lt;/h2&gt;
&lt;p&gt;由于函数组件每次更新都会完整执行函数体，我们需要一些优化手段：&lt;/p&gt;</description></item><item><title>react 组件设计模式</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-021/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/react/react-021/</guid><description>&lt;p&gt;首先我们想一个问题，那就是 &lt;strong&gt;为什么要学习设计模式？&lt;/strong&gt; 原因我总结有以下几个方面。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 功能复杂，逻辑复用问题。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;首先 React 灵活多变性，就决定了 React 项目可以应用多种设计模式。但是这些设计模式的产生也确实办了实事:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;场景一：&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在一个项目中，全局有一个状态，可以称之为 theme （主题），那么有很多 UI 功能组件需要这个主题，而且这个主题是可以切换的，就像 github 切换暗黑模式一样，那么如何优雅的实现这个功能呢？&lt;/p&gt;
&lt;p&gt;这个场景如果我们用 React 的&lt;strong&gt;提供者模式&lt;/strong&gt;，就能轻松搞定了，通过 &lt;code&gt;context&lt;/code&gt; 保存全局的主题，然后将 &lt;code&gt;theme&lt;/code&gt; 通过 &lt;code&gt;Provider&lt;/code&gt; 形式传递下去，需要 theme ，那么消费 context ，就可以了，这样的好处是，只要 theme 改变，消费 context 的组件就会重新更新，达到了切换主题的目的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;场景二：&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;表单设计场景也需要一定程度上的 React 的设计模式，首先对于表单状态的整体验证需要外层的 &lt;code&gt;Form&lt;/code&gt; 绑定事件控制，调度表单的状态下发，验证功能。内层对于每一个表单控件还需要 &lt;code&gt;FormItem&lt;/code&gt; 收集数据，让控件变成受控的。 这样的 &lt;code&gt;Form&lt;/code&gt; 和 &lt;code&gt;FormItem&lt;/code&gt; 方式，就是通过&lt;strong&gt;组合模式&lt;/strong&gt;实现的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 培养设计能力，编程能力&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;熟练运用 React 的设计模式，可以培养开发者的设计能力，比如 &lt;strong&gt;&lt;code&gt;HOC&lt;/code&gt; 的设计&lt;/strong&gt; ，&lt;strong&gt;公共组件的设计&lt;/strong&gt; ，&lt;strong&gt;自定义 hooks 的设计&lt;/strong&gt;，一些开源的优秀的库就是通过 React 的灵活性和优秀的设计模式实现的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;例子：&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;比如在 React 状态管理工具中，无论是 &lt;code&gt;react-redux&lt;/code&gt; ，还是 &lt;code&gt;mobx-react&lt;/code&gt;，一方面想要把 &lt;code&gt;state&lt;/code&gt; 和 &lt;code&gt;dispatch&lt;/code&gt; 函数传递给组件，另一方面订阅 state 变化，来促使业务组件更新，那么整个流程中，需要一个或多个 HOC 来搞定。于是 react-redux 提供了 &lt;code&gt;connect&lt;/code&gt;，mobx-react 提供了 &lt;code&gt;inject&lt;/code&gt; ，&lt;code&gt;observer&lt;/code&gt; 等优秀的 hoc。由此可见，学会 React 的设计模式，有助于开发者小到编写公共组件，大到开发开源项目。&lt;/p&gt;</description></item></channel></rss>