我有一个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 }
这是一个上下文问题。
运行
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
与状态保持同步。