<?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 渲染机制 on Last Stand</title><link>https://amatsuzero.github.io/LastStand/tags/react-%E6%B8%B2%E6%9F%93%E6%9C%BA%E5%88%B6/</link><description>Recent content in React 渲染机制 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/tags/react-%E6%B8%B2%E6%9F%93%E6%9C%BA%E5%88%B6/index.xml" rel="self" type="application/rss+xml"/><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></channel></rss>