我在反应组件中有这个功能
const updateDesc = useCallback(
(text: string) => {
const tval = text.trim()
if (tval === '<p></p>' && !view.description?.trim()) return
if (tval === view.description?.trim() ?? '') return
const next = {
...view,
description: tval
}
onChange?.(next)
},
[view]
)
我就是这么称呼它的:
<MyComponent onBlur={text => updateDesc(text)} />
但问题是,在 updateDesc 中,视图保存的是视图之前的值,而不是最新的,如果我之前更改了标题,然后更改描述,标题将恢复为之前的值。
我尝试删除 useCallback,但问题仍然存在。这对我来说看起来很奇怪,因为我希望该函数具有最新的视图值,因为它是在视图更改时重新创建的。我最终通过裁判解决了这个问题,但我的问题仍然存在,为什么会发生这种情况?有人可以启发我吗
渲染后的状态是快照。它具有相对于最新渲染的值,而不是相对于最新更改的值。另请注意,事件中的状态更新器不会立即直接触发新的渲染,而是将渲染排队。实际渲染仅在完成当前事件后开始。 这一点必须非常重要地注意。请参阅下面一个非常简单的示例代码以及测试运行结果。 结果显示,当前渲染或快照中的状态与排队的下一个渲染的最新值滞后 1。
应用程序.js
import { useState } from 'react';
export default function App() {
const [a, setA] = useState(0);
function handleChange(newValue) {
console.log(`state during the event : ${a}`);
setA(newValue);
}
return (
<>
look at the console for the state value during the render:
<br></br>
look here for the state value after the event or render : {a}
<br />
<button
onClick={() => {
handleChange(a + 1);
}}
>
Change State by 1
</button>
</>
);
}
试运行
在同一事件中处理一系列状态更新。
我们上面已经讨论过,事件中的状态更新不会立即触发另一个渲染,而是将新的渲染排队,并且仅在完成当前事件后不久开始的实际渲染上处理如此排队的状态更新。因此,如果一个事件中有一系列的状态更新,则必须配备更新器功能,如下所示。该事件调用状态更新两次,第二次调用已配备更新器功能。需要从之前的调用中获取最新值。 但是,基本原则仍然成立,即在渲染期间,状态值将相对于快照,而不是相对于事件中的最新状态更新。
App.js
import { useState } from 'react';
export default function App() {
const [a, setA] = useState(0);
function handleChange(newValue) {
console.log(`state during the event : ${a}`);
setA(newValue);
}
return (
<>
look at the console for the state value during the render:
<br></br>
look here for the state value after the event or render : {a}
<br />
<button
onClick={() => {
handleChange(a + 1);
handleChange((a) => a + 1);
}}
>
Change State by 2
</button>
</>
);
}
试运行
关于参考和状态的注释
Refs 将在渲染之间保留,但是 Refs 中的更改不会触发新的渲染。另一方面,状态除了在渲染之间保留之外,还将触发新的渲染。另请注意 Ref 是 React 世界的逃生口,因此它可以作为最后的手段。