在 event.preventDefault() 之后调用函数时响应发送过时状态

问题描述 投票:0回答:1

我有一个react + mobx + MaterialUI 前端,我面临着涉及状态变量的问题。我有一个按钮应该触发一个函数,该函数将一些状态变量转换为一个对象,并向其发送其他将处理后续步骤的对象。当我单击按钮时,对象创建正常。但是,当点击输入事件触发相同的函数时,该对象具有空值(尽管当我 consoloe.log 记录的值的状态值是正确的) 代码:

 useEffect(() => {
    window.addEventListener("keydown", handleKeyPress);
    return () => {
      window.removeEventListener("keydown", handleKeyPress);
    };
  }, []);
  const handleKeyPress = (e: any) => {
    if (e.key === "Enter") {
      e.preventDefault();
      handleSendPing();
    }
  };
  const handleSendPing = () => {
    if (userStore.user) {
      var ping: NewPingDto = {
        recipient: selectedUser,
        locationName: selectedLocation,
        pingMessage: selectedPingMessage,
        senderId: userStore.user.id,
        companyId: userStore.user.companyId,
        dateCreated: new Date(),
        dateLastModified: new Date(),
        isExpired: false,
        isUrgent: urgentPing,
        pingResponse: "",
        isRead: false,
      };
      console.log("foo", ping);
      pingStore.addPing(ping);
    }
  };
  useEffect(() => {
    console.log("new selectedUser", selectedUser);
  }, [selectedUser]);

所有按钮都有 type="button",所以不是意外提交导致的(页面中也没有 form 元素。useEffect 钩子显示 selectedUser 不是 "" 当我按回车键时打印反对:

  {
    "recipient": "",
    "locationName": "",
    "pingMessage": "",
    "senderId": "c0a0d5a0-ffaf-4b7e-8f4a-6b6b8b7b8b71",
    "companyId": 1,
    "dateCreated": "2023-08-21T17:39:25.014Z",
    "dateLastModified": "2023-08-21T17:39:25.014Z",
    "isExpired": false,
    "isUrgent": false,
    "pingResponse": "",
    "isRead": false }
javascript html reactjs typescript mobx
1个回答
0
投票

这是一个上下文问题。

运行

useEffect
window.addEventListener("keydown", handleKeyPress)
没有任何依赖项,因此它仅在组件安装时运行一次。

此时,

handleKeyPress
引用了一个调用另一个函数
handleSendPing
的函数。此时,另一个
handleSendPing
函数的闭包只能看到这些状态变量的初始值(
selectedUser
selectedUser
,...),这可能是
undefined
或类似的东西(例如空字符串)。

一个快速修复可能是将

handleKeyPress
添加为运行
useEffect
window.addEventListener("keydown", handleKeyPress)
的依赖项,以便每次重新创建
keydown
时(在每次渲染上)都会删除并再次添加
handleKeyPress
事件,保持闭包中的状态变量与最新状态同步:

useEffect(() => {
  window.addEventListener("keydown", handleKeyPress);

  return () => {
    window.removeEventListener("keydown", handleKeyPress);
  };
}, [handleKeyPress]);

或者,只需使用

handleSendPing
授予
ref
对状态的访问权限。这个
ref
将存储
handleSendPing
需要的所有存储变量,并使用
useEffect
与状态保持同步。

© www.soinside.com 2019 - 2024. All rights reserved.