我在useState
React hook中遇到了一些非常奇怪的行为。在下面的代码中(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);
单击按钮
时,我们在控制台中获得以下序列:
one
two
zero
我希望:
zero
one
zero
two
因为我认为如果React找到useState
setter并在重新渲染后执行以下代码,它会立即重新渲染。此外,我的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
值与状态变量time
的内容不同时,上述代码会发生什么情况:
Hey
Hello
换句话说,重新呈现首先运行,setter之后运行代码。那么,为什么在上述情况下我们会有不同的行为呢?解释是什么?引擎盖下发生了什么?
const setBoth = () => {
setRunning(true);
setJumping(true);
};
上述代码称为批处理。这意味着通过同时调用setRunning和setJumping,react、幕后更新。这将导致一次重新渲染。
因此,当您单击更改两种状态的按钮时,两种状态将同时设置。因此我们印刷
// "1"
//"2"
//"3" =======
UseEffect是在重新渲染后调用的react挂钩。
因此,首先打印“嘿”=====
接下来,将调用useEffect,因为重新渲染后react将调用useEffect。
因此它会打印“你好”。
这是预期的行为,通常仅当状态或道具更改时才重新渲染组件。React的useState
是一个异步函数,这就是console.log订单不匹配的原因。
您可以使用useffect
收听更改并根据需要启动函数。
Codesandbox链接
const Comp = ({ flag }) => {
const [running, setRunning] = useState(false);
const [jumping, setJumping] = useState(false);
const setZero = () => {
console.log("zero");
};
useEffect(() => {
setJumping(!running);
console.log("two");
}, [running]);
const setBoth = () => {
setZero();
setRunning(!running);
console.log("one");
};
return (
<>
<pre>{JSON.stringify({ running, jumping })}</pre>
<button onClick={() => setBoth()}>setboth</button>
</>
);
};
-第一个问题
根据丹·阿布拉莫夫(联合创始人:Redux,创建React应用程序)的说法
目前(React 16及更早版本),默认情况下只有React事件处理程序中的更新是批处理的。有一个不稳定的API,当您需要时,可以在事件处理程序之外强制批处理。
不管你在React事件处理程序中调用了多少setState()组件,它们在事件结束时只会产生一个重新渲染
在第一种情况下,click事件是一个react事件
-第二个问题
根据丹·阿布拉莫夫的说法
但是,无论是在React 16还是更早的版本中,在React事件处理程序之外,默认情况下都没有批处理。因此,如果在您的示例中我们使用了AJAX响应处理程序而不是handleClick,那么每个setState()都会在发生时立即被处理。在这种情况下,是的,您将看到一个中间状态:
window.addEventListener不是react事件,因此应立即呈现它。
你可以在这里找到Dan Abramov的完整答案
我在这里举了一个包含这两个场景的示例
问题内容: 在带有钩子的React中,更新状态的正确方法是嵌套对象是什么? 一个人怎么会使用到的更新来(附加一个字段)? (改变价值)? 问题答案: 您可以像这样传递新值
我有一个表单组件,它从其父级获取其状态。表单组件只呈现一些输入字段和其他字段。 父组件使用useReucer并将值向下传递给表单组件。 有两个父组件,一个允许用户使用表单创建,另一个允许他们编辑。 在编辑父组件中,我使用useEffect从api获取数据,并从服务器设置初始状态。 在开发构建中,当组件呈现时,有时会出现以下错误: 超过最大更新深度。当组件在componentWillUpdate或c
更新状态的正确方式是什么,是一个嵌套对象,在与钩子反应? 如何使用将更新为(附加字段)? (更改值)?
我正在尝试新的hooks功能,并坚持认为我的状态没有更新。 实际上,状态已更新(我可以在console.log中看到更新的值,并且我的组件会重新运行useEffect),但是useEffect方法使用我的旧状态,并仅将签名保存给第一个用户,而活动用户在状态中确实发生了更改。 我想过添加useCallback,并将我的方法移动到use效果或组件本身,但我可以设法让它工作。 状态: 这是我的效果: 这
因此,我有一些代码并没有像预期的那样工作。当前焦点是在父组件上使用useState()设置的,因此它是一个状态变量。但是,当父级中的currentFocus值更改时,此处的focus变量本身不会更新。我希望重新呈现父组件,这反过来会重新呈现该组件,从而导致foucs值发生更改。 现在我可以通过执行以下操作来解决此问题, 但我只想在更新focus/currentFocus时运行useEffect挂钩