React中useState的setState异步行为问题咨询
这不是useState的Bug,是它的异步特性导致的!
你遇到的这个情况完全是正常的,useState的setState是异步更新的,这是React为了性能优化设计的特性,不是Bug哦~
为什么会出现“旧值”问题?
当你调用setHandle(e.target.value)时,React并不会立刻更新handle状态,而是会把这次更新加入到更新队列中,等待合适的时机批量处理。所以在同一个事件回调里,你紧接着访问handle,拿到的还是更新前的旧值(来自当前渲染周期的闭包),这就导致你的校验逻辑用了旧的状态,必须等下一次渲染才能生效。
你的代码怎么改?
其实很简单,既然handle还没更新,你直接用e.target.value(也就是最新的输入值)来做校验就行了,没必要依赖还没更新的状态。修改后的代码如下:
<TextField label="Username" value={handle} error={error.hasError} id="username" onChange={e => { const inputValue = e.target.value; setHandle(inputValue); console.log("Ran"); // 直接用inputValue做校验,而不是handle for (let i = 0; i < inputValue.length; i++) { if (!isAllowedChar(inputValue[i])) { return setError({ message: "Username should only contain alphabets, digits, _ and .", hasError: true }); } } setError({ message: "", hasError: false }); }} />
额外补充:如果确实需要依赖更新后的状态怎么办?
如果你的逻辑必须在handle更新完成后执行,可以用useEffect钩子,监听handle的变化:
useEffect(() => { // 这里的handle是更新后的最新值 let isValid = true; for (let i = 0; i < handle.length; i++) { if (!isAllowedChar(handle[i])) { isValid = false; break; } } setError({ message: isValid ? "" : "Username should only contain alphabets, digits, _ and .", hasError: !isValid }); }, [handle]); // 只有handle变化时才触发
这样就能保证每次handle更新后,校验逻辑都会用最新的值执行啦~
内容的提问来源于stack exchange,提问作者Prince Sule
相关产品推荐
相关产品推荐

