reactjs - useState React 钩子的奇怪行为
问题描述
我在使用useState
React 钩子时遇到了一些非常奇怪的行为。在以下代码中(https://codesandbox.io/s/purple-bush-nb5uy?file=/src/index.js):
function App() {
return (
<div className="App">
<Comp flag={true} />
</div>
);
}
const Comp = ({ flag }) => {
const [running, setRunning] = useState(false);
const [jumping, setJumping] = useState(false);
console.log('zero');
const setBoth = () => {
setRunning(true);
console.log('one');
setJumping(true);
console.log('two');
};
return (
<>
{"running: " + running}
{"jumping: " + jumping}
<button onClick={() => setBoth()}>setboth</button>
</>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
当我们单击 时button
,我们会在控制台中输入以下序列:
one
two
zero
我希望:
zero
one
zero
two
因为我认为如果 React 找到一个useState
设置器,它会立即重新渲染,并且在重新渲染后执行以下代码。此外,我的 React 应用程序就是这种情况:
const [time, setTime] = useState('');
console.log('Hey');
const updateTime = (e) => {
setTime(e.details);
console.log('Hello');
};
useEffect(() => {
window.addEventListener("updateTime", updateTime);
return () => {
window.removeEventListener("updateTime", updateTime);
}
}, []);
上面的代码在updateTime
运行时以及当e.details
value 与 state variabletime
的内容不同时会发生什么:
Hey
Hello
换句话说,首先运行重新渲染,然后运行 setter 之后的代码。那么,为什么我们在上述情况下会有不同的行为呢?解释是什么?幕后发生了什么?
解决方案
-第一个问题
根据Dan Abramov(共同创建者:Redux,创建 React 应用程序。)
目前(React 16 和更早版本),默认情况下,仅对 React 事件处理程序内的更新进行批处理。有一个不稳定的 API 可以在您需要的极少数情况下强制在事件处理程序之外进行批处理。
无论您在 React 事件处理程序中执行多少个组件中的多少个 setState() 调用,它们都只会在事件结束时产生一次重新渲染
在你的第一种情况下,点击事件是一个反应事件
-第二个问题
根据丹·阿布拉莫夫
但是,在 React 16 和更早的版本中,默认情况下在 React 事件处理程序之外还没有批处理。因此,如果在您的示例中我们有一个 AJAX 响应处理程序而不是 handleClick,则每个 setState() 都会在发生时立即处理。在这种情况下,是的,您会看到一个中间状态:
window.addEventListener 不是反应事件,所以应该立即渲染。
你可以在 这里找到Dan Abramov的完整答案
我在这里做了一个包含两个场景的例子
推荐阅读
- laravel - 使用宅基地的最新版本的流明(Laravel)基准测试较少
- html - 下拉表单在boostrap 3中重叠
- javascript - 如何让 for 循环创建一个由 9 个随机 1 位数字组成的字符串?
- ckeditor - 给 CKEditor “需要编辑器插件”错误的撇号站点
- amazon-web-services - 从 AMI 恢复时状态检查失败的 WIndows EC2 实例
- excel - 在记事本++中按字符将行数据转置为列
- c# - 为什么 (int)==(float) 总是编译为 (float)==(float)
- r - 使用 grepl 对 [:alpha:]:[:punct:] 进行数据清理
- javascript - 我在表单上捕获提交按钮的代码有效,但我做得正确吗?
- php - 如何在blade.php中使用vue获取字段的旧值