React.useCallback未使用依赖项进行更新



我正在使用以下组件在我的应用程序中提交评论:

const App = () => {
const [text, setText] = React.useState("");
const send = React.useCallback(() => {
setText("");
console.log("sending", text);
}, [text]);
React.useEffect(() => {
const handler = e => {
switch (e.keyCode) {
case 13: // enter
if (e.shiftKey) {
e.preventDefault();
send();
}
break;
}
}

document.addEventListener("keydown", handler);
return () => document.removeEventListener("keydown", handler);
}, []);
return <div className="App">
<textarea
className="App__text"
value={text}
onChange={e => {
setText(e.target.value);
}} />
<button className="App__send" onClick={send}>send</button>
</div>;
};

此处的工作演示

这是一个简单的文本字段和按钮。当按下按钮或shift-enter时,文本字段中的文本将发送到服务器(这里我们只是console.log(。

该按钮工作正常-输入"hello world"(或其他(按下该按钮,控制台将显示hello world

不过,Shift-enter总是打印一个空字符串

我猜我误解了useCallback。据我所知,useCallback封装了您的函数。当其中一个依赖项发生更改时,React会在不更改包装器函数的情况下交换您的函数,因此无论在哪里使用,它都是最新的引用。考虑到在useEffect中调用的send似乎在范围中具有text的初始值,但在buttononClick中使用的值是最新的,我的假设似乎是不正确的。

我还尝试添加text作为useEffect的依赖项,但

  • 我不想在每次击键时删除/创建/添加侦听器
  • 它仍然缺少最后一个按下的字符

如何将send函数的当前版本保留在另一个回调中

您的依赖项中缺少send,请查看以下更新的代码:

React.useEffect(() => {
const handler = e => {
switch (e.keyCode) {
case 13: // enter
if (e.shiftKey) {
e.preventDefault();
send(); // This will always be called an older version, instead of updated one
}
break;
}
}
document.addEventListener("keydown", handler);
return () => document.removeEventListener("keydown", handler);
}, [send]); // You need to put send here, since it is part of this component, and needs to be updated

它之所以能使用它,是因为send功能也被记忆了:

const send = React.useCallback(() => {
setText("");
console.log("sending", text);
}, [text]);

所以你需要确保更新到它的新版本,用它的新文本(这从未发生过,这就是为什么你在SHIFT+ENTER中没有文本(

EDIT:经过进一步调查,在我看来,最大的问题是文本和侦听器处理程序不同步

我已经修改了代码,将侦听器全部删除,并直接在文本区域使用onKeyDown道具。看看这个工作代码笔:

https://codepen.io/antonioerda/pen/zYqYWgx

使用useCallback钩子时需要确保做两件事:

  1. 请确保添加所有所需依赖项的列表,这些依赖项都在方法外部
  2. 如果在这个带有usecallback的方法中,您调用了另一个使用usecallback创建的方法,那么在这个方法中也包括依赖项

最新更新