React中在Effect Hook内更新document.title的底层原理及疑问
React Effect Hook 相关疑问解答
先看你提到的官方示例代码:
import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // Similar to componentDidMount and componentDidUpdate: useEffect(() => { // Update the document title using the browser API document.title = `You clicked ${count} times`; }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
针对你的三个疑问,解答如下:
1. Effect Hook内更新document.title的底层逻辑,以及外部执行的问题
useEffect的执行时机是组件渲染完成、真实DOM更新之后,此时组件的状态(比如count)已经是最新值,能确保标题和页面显示的点击次数完全一致。
如果在组件函数顶层直接执行document.title = ...,会带来这些问题:
- 每次组件渲染(包括初始渲染和状态更新后的重渲染)都会执行,即使状态没变化也会重复修改标题,造成不必要的性能浪费;
- 渲染过程是React的纯计算阶段,此时真实DOM还没更新,若依赖的状态在渲染中发生变化,可能拿到旧值,导致标题和页面内容不一致;
- 在服务端渲染场景下,服务端没有
document对象,直接执行会抛出错误。
另外,React要求组件函数是纯函数(给定相同输入返回相同输出,无副作用),顶层执行副作用会破坏这个特性,导致渲染行为不可预测。
2. 标签是否包含在React的Virtual DOM中 <a class="header-anchor" href="#_2-标签是否包含在react的virtual-dom中" aria-hidden="true">#</a></h2>
<p>默认情况下,我们编写的组件树里不会包含<code><title></code>标签,所以它不在组件的Virtual DOM范围内。</p>
<p>不过在一些框架(比如Next.js、Gatsby)中,会提供专门的组件(如<code>next/head</code>)来管理页面头部元素,这时<code><title></code>会被纳入React的Virtual DOM,由React通过协调流程来更新。但原生React中,直接通过<code>document.title</code>修改是绕开Virtual DOM的,因为<code><title></code>不在我们定义的组件结构里。</p>
<h2 id="_3-与reactdom的reconciliation(协调)流程的关系">3. 与ReactDOM的Reconciliation(协调)流程的关系 <a class="header-anchor" href="#_3-与reactdom的reconciliation(协调)流程的关系" aria-hidden="true">#</a></h2>
<p><code>useEffect</code>和Reconciliation流程是紧密关联的:<br>
Reconciliation是React对比新旧Virtual DOM、计算差异并更新真实DOM的过程,<strong>Effect Hook会在Reconciliation完成、真实DOM更新后执行</strong>,这样能保证副作用操作依赖的DOM和状态都是最新的。</p>
<p>而直接更新<code>document.title</code>本身不属于Reconciliation流程,因为<code><title></code>不在Virtual DOM中。但<code>useEffect</code>的执行时机是在协调完成后,避免了副作用操作和DOM更新过程冲突,确保操作的准确性。</p>
<hr>
<p>内容的提问来源于stack exchange,提问作者Salomon Perez Ventura</p>
相关产品推荐
相关产品推荐

