首页 > 解决方案 > 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 会在不更改包装函数的情况下换出你的函数,因此无论在何处使用它,它仍然是最新的参考。鉴于send被调用useEffect的初始值似乎text在范围内,但在onClickof中使用的值button是最新的,我的假设似乎不正确。

我也尝试添加text作为useEffect但是的依赖项

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

标签: reactjsreact-hooks

解决方案


您缺少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 中没有文本的原因)

编辑:经过进一步调查,在我看来,最大的问题是不同步的 text 和 listener handler

我已经修改了代码以使其工作,通过一起删除侦听器,并onKeyDown直接在 textarea 上使用 prop。看看这个工作的codepen:

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


推荐阅读