我应该使用 useEffect() 进行 dom 操作还是直接进行操作?

web*_*ect 7 reactjs

React 文档中,我看到了这段代码

function Example() {
  const [count, setCount] = useState(0);

  //THE SUBJECT OF MY QUESTION:
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是为什么不使用 useEffect 更改 document.title 或任何其他 DOM,如下所示:

function Example() {
  const [count, setCount] = useState(0);

  //THE SUBJECT OF MY QUESTION:
  document.title = `You clicked ${count} times`;

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

我知道例如发送请求时,它是异步的,我们需要在 useEffect 中进行。但是DOM操作不是异步的,时间相对为0,那为什么还要使用useEffect钩子呢?

Den*_*ash 5

几乎是一样的,参见我的相关回答,useEffect深入

区别在于一个值得注意的“陷阱”,即在渲染阶段之后useEffect执行的回调。

const App = () => {
  useEffect(() => {
    console.log("executed after render phase");
  });

  console.log("executed at render phase");

  return <></>;
};
Run Code Online (Sandbox Code Playgroud)

将导致:

executed at render phase
executed after render phase
Run Code Online (Sandbox Code Playgroud)

编辑 useEffect 执行阶段


for*_*d04 5

您最好将 DOM 操作和其他副作用保留在内部useEffect

\n\n
useEffect(() => {\n    document.title = `You clicked ${count} times`;\n}, [count]); // set your dependencies\n
Run Code Online (Sandbox Code Playgroud)\n\n

原因是:这种方法符合React Strict Mode和即将推出的Concurrent Mode

\n\n

什么是并发模式:

\n\n
\n

[...] React 可能会在提交之前多次调用渲染阶段生命周期,或者可能根本不提交就调用它们(由于错误或更高优先级的中断)。

\n
\n\n

在您的情况下,document.title分配可能会重复多次,或者 React 甚至可能决定中止整个提交。一般来说,这可能会导致不一致:

\n\n
\n

由于上述方法可能会被多次调用,因此重要的是它们包含副作用。忽略此规则可能会导致各种问题,包括内存泄漏和无效的应用程序状态。(文档

\n
\n