考虑典型的useState
示例:
import React, { useState } from 'react';
const MyComponent = () => {
const [count, setCount] = useState(0);
console.log(count);
return (
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
count: {count}
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
export default MyComponent;
单击按钮可使每个状态打印两次。为什么呢?
答案 0 :(得分:10)
将console.log
放在没有依赖项的useEffect
挂钩中,您会发现它实际上实际上渲染两次。
import React, { useEffect, useState } from 'react';
const MyComponent = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(count);
});
return (
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
count: {count}
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
export default MyComponent;
这是一个很好的组件生命周期图,它列出了基于类的生命周期函数,但是呈现/提交阶段是相同的。
要注意的导入事项是可以在不实际提交的情况下“渲染”组件(即,您在屏幕上看到的常规渲染)。仅console.log就是其中的一部分。效果在“提交”阶段之后运行。
...传递给useEffect的函数将运行 将渲染提交到屏幕后。 ...
默认情况下,效果会在每个完成的渲染之后运行,...
Detecting Unexpected Side-effects
严格模式无法自动为您检测副作用,但是 可以使它们更具确定性,从而帮助您发现它们。 这是通过有意重复调用以下功能来完成的:
- 类组件
constructor
,render
和shouldComponentUpdate
方法- 类组件静态
getDerivedStateFromProps
方法- 功能组件主体
- 状态更新程序功能(
setState
的第一个参数)- 传递给
useState
,useMemo
或useReducer
的功能
这仅适用于开发模式。
答案 1 :(得分:2)
有关双重重发的更多信息(根据封闭的反应问题)。
这是StrictMode的故意功能。这仅在开发过程中发生,并有助于发现进入渲染阶段的意外副作用。我们只对具有Hooks的组件执行此操作,因为这些组件很可能在错误的地方意外地产生了副作用。
https://github.com/facebook/react/issues/15074
另一个相关的问题在这里。
答案 2 :(得分:0)
const countRef = useRef(1);
countRef.current += 1;
这种方式渲染会一次执行2次
const countRef = useRef(1);
useEffect(() => {
countRef.current += 1;
})
这种渲染方式一次执行1次