gpt4 book ai didi

javascript - window.localStorage.setItem 未在 onkeydown 回调中执行

转载 作者:行者123 更新时间:2023-12-05 05:40:26 25 4
gpt4 key购买 nike

我正在尝试在我的 react 应用程序中实现 onkeydown 事件处理程序,以通过按 ESC 关闭设置屏幕:

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

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

const saveSettings = () => {
window.localStorage.setItem("storage.ls.version", CURRENT_LOCALSTORAGE_SCHEMA_VERSION);

window.localStorage.setItem("auth.token", authInput);
window.localStorage.setItem("filter.class", classInput);
window.localStorage.setItem(
"filter.subjects",
JSON.stringify(subjectsInput.filter((v: string) => v.trim() !== ""))
);

props.dismiss();
};

const handleKeyPress = (event: KeyboardEvent) => {
if (event.key === "Escape") {
saveSettings();
}
};

回调确实执行了,props.dismiss()(在 saveSettings 中)运行得很好。但是这些更改似乎没有保存到 localStorage。但是,当我在按下按钮时使用相同的 saveSettings 功能(我之前已经这样做过)时,它会按预期工作并保存。

我没能找到一些东西,但是是否存在阻止在事件回调中使用 localStorage 的限制?或者是否有其他原因无法按预期工作?


查看问题下的评论线程;这是读取 localStorage 的代码:

const [authInput, setAuthInput] = useState(window.localStorage.getItem("auth.token") ?? "");

const [classInput, setClassInput] = useState(window.localStorage.getItem("filter.class") ?? "");
const [subjectsInput, setSubjectsInput] = useState(
JSON.parse(window.localStorage.getItem("filter.subjects") ?? "[]")
);

最佳答案

这里有几个问题导致了您的问题:

  1. handleKeyPress 函数被绑定(bind)为第一个 useEffectkeydown 事件的事件处理程序,因此它保存了当时的上下文它运行的时间点。假设您在本地存储中已经有了 authInput = appleclassInput = englishsubjectsInput = '' 等值,您将值更改为authInput = banana,然后你点击ESC,将存储在authInput中的值将再次是apple,因为当您将 handleKeyPress 附加到 DOM 中的 keydown 事件时,这是 authInput 的初始值,并且始终为 apple!所以它“看起来”好像无论你做什么,值(value)都不会改变。要解决此问题,您需要添加 handleKeyPress 作为第一个 useEffect() 的依赖项。此函数上下文随着每次状态更改而更改,因为 saveSettings() 函数对 authInputclassInput 及其引用的所有其他值具有不同的值,每当状态改变时。因此,您需要进行的第一项更改如下:
  useEffect(() => {
document.addEventListener("keydown", handleKeyPress, false);

return () => {
document.removeEventListener("keydown", handleKeyPress, false);
};
}, [handleKeyPress]); // add the function as a dependency
  1. handleKeyPress 如果它在内部引用的值/函数没有改变,则不需要改变。所以使用 React 的 useCallback() 来指定这个关系:
  const handleKeyPress = useCallback((event) => {
if (event.key === "Escape") {
saveSettings();
}
}, [saveSettings]);

参见 https://reactjs.org/docs/hooks-reference.html#usecallback有关更多信息。

  1. 最后,对 saveSettings() 应用相同的处理,因为该函数取决于三个值:
  const saveSettings = useCallback(() => {
window.localStorage.setItem("storage.ls.version", CURRENT_LOCALSTORAGE_SCHEMA_VERSION);

window.localStorage.setItem("auth.token", authInput);
window.localStorage.setItem("filter.class", classInput);
window.localStorage.setItem(
"filter.subjects",
JSON.stringify(subjectsInput.filter((v: string) => v.trim() !== ""))
);

props.dismiss();
}, [authInput, classInput, subjectsInput]);

每当 authInputclassInputsubjectsInput 的状态发生变化时,React 将运行您在 useEffect( ) 并使用在其运行时上下文中具有正确状态值的新处理程序重新运行效果。

如果您仍然不明白为什么会这样,没关系!不要担心 - 我强烈建议您阅读闭包在 Javascript 中的工作原理:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closureshttps://javascript.info/closure

最后,我想为您提一些您可能想要清理的代码味道:

  1. 在为所有状态变量设置初始状态时,将从 localStorage 读取的昂贵操作包装在一个函数中,这样 React 只运行一次,而不是每次重新渲染。
const [authInput, setAuthInput] = useState(window.localStorage.getItem("auth.token") ?? "");

// instead do this
const [authInput, setAuthInput] = useState(() => window.localStorage.getItem("auth.token") ?? "");
  1. 当您在 saveSettings() 中对其运行 filter() 时,subjectsInput 是否保证是一个数组?您可能需要考虑这一点。

关于javascript - window.localStorage.setItem 未在 onkeydown 回调中执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72431033/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com