本文旨在讨论 React 中的 render(渲染) 一词的含义?react
若是你已经接触了 React 一段时间,你常常会看到 render(渲染),rerender(重渲染),等各类与渲染相关的字眼,当我做为一个菜鸟时,我时常为这些字眼发愁,尽管我知道这些词语的本意,可是却不明白它们在 React 中表明什么。如今,通过必定量的学习,我以为本身终于能够看清一部分,借此分享出来,以期帮助别人,同时也是借此梳理下本身掌握的知识。数组
为了理解 render 在 React 中表明什么,咱们须要稍微深刻下 React 的工做原理,也许你已经知道虚拟DOM,Diff,等各类新奇的词语,不过仍是让咱们按顺序梳理如下。dom
React 进行渲染的 时机 有两种(其实也能够算一种,其中一种只是另外一种的变体):函数
挂载,React 调用类组件 DidComponentMount 生命周期方法时,或者函数组件的useEffect中回调函数第一次执行的时候,能够认为已经发生了挂载。学习
更新,React 调用类组件的 DidComponentUpdate 的时候,或者函数组件被从新执行时,均可以认为是发生了重渲染。spa
咱们首先来看组件更新的状况,而后再回头看挂载的状况,你会发现,后者和前者的差异其实很小,这也是为何 React 在函数组件里提供的 useEffect hook 再也不区分挂载和更新。code
让咱们使用经典的计数器例子生命周期
// 警告:为了代码的精简的,我省略了 useCallback 包裹回调函数的行为
function Counter() {
const [count, setCount] = useState();
return (
<div>
<span className="count">{count}</span>
<button onClick={() => setCount(prev => prev + 1)}>INC<button>
</div>
);
}
复制代码
在 Counter 挂载后,当你点击了 INC 按钮时,就会触发一次 React 的组件的更新 或者说是重渲染。jsx
这里为了讲解的方便,我自做主张的将 React 的一个完整的渲染周期的分为三个阶段,注意不要联想到生命周期,这里没有任何关系。回调函数
三个阶段是:
渲染函数阶段 或 render函数阶段,这个阶段会执行render函数,生成虚拟DOM。
tree diff 阶段,这个阶段 React 会对比新旧的的虚拟DOM,看看是否有变化发生。
commit 阶段,若是确实发生了变化,才会进入这个阶段,这个阶段会将虚拟DOM中发生的变化同步到真实DOM上。
通常来讲,前两个阶段能够视为一个阶段,由于它们都发生在虚拟DOM层面,而且一旦触发渲染函数阶段,则必定会触发 tree diff 阶段,可是 commit 阶段只在虚拟DOM发生变化的时才能够被触发。
在了解组件更新的的流程后,咱们对比着更新的流程,回过头来看组件挂载的状况:
答案: 确定有!必需要执行 render 函数,生成虚拟DOM。
答案:这里视场景有不一样的答案,不严谨的说,ReactDOM.render() 是没有这个阶段的,由于首次执行还不存在能够进行对比的旧虚拟DOM,会直接跳到 commit 阶段。而其余挂载的状况,被挂载的组件自身也是不会进行 tree diff 的。
这里为了不误解多说一点,父组件更新致使某个子组件被挂载或卸载,子组件挂载时自身是不会进行 tree diff 的,视状况会直接跳到 commit 阶段或就此结束。可是父组件进行 tree diff 时会用到这个子组件。你能够认为 null 指是一个特殊的虚拟DOM,React 将它做为占位符使用,在进行 tree diff 的时候也有相关的做用。
答案:这点毋庸置疑。
如今,让咱们经过肯定 “这个组件发生了渲染/重渲染/无用的重渲染” 是什么意思来解答本小节的问题。
对于 ...发生了渲染/重渲染 来讲都是指阶段123,也就是整个渲染阶段。生成变化后的虚拟DOM,进行 tree diff,将变化 commit 到真实 DOM 上。若是不是在指明讨论虚拟 DOM 的话,将渲染一词局限一、2阶段时没有意义的。
而对于 发生了无效的重渲染 来讲,是指阶段一、2。通常发生在父组件发生了更新,子组件的props却没有变化,因此子组件生成的虚拟dom没有发生改变,在 tree diff 阶段后直接断掉了,没有进入 commit 阶段。
之后再碰到与 React 渲染相关的问题,能够直接用上文讲解的三个阶段往上套,经过理解上下文,应该能够很容易理解做者想要的强调有关渲染的什么方面。