我正在使用以下组件在我的应用程序中提交评论:
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
的初始值,但在button
的onClick
中使用的值是最新的,我的假设似乎是不正确的。
我还尝试添加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钩子时需要确保做两件事:
- 请确保添加所有所需依赖项的列表,这些依赖项都在方法外部
- 如果在这个带有usecallback的方法中,您调用了另一个使用usecallback创建的方法,那么在这个方法中也包括依赖项