gpt4 book ai didi

javascript - React/Redux、useEffect/useSelector、陈旧的闭包和事件监听器

转载 作者:行者123 更新时间:2023-12-01 23:04:12 26 4
gpt4 key购买 nike

我有一个 React/Redux 类组件,我正在将其转换为功能组件。

以前,它有一个 componentDidMount 回调,它为从应用中其他地方调度的自定义事件添加了一个事件监听器。这将被替换为 useEffect。事件监听器在触发时调用此组件中其他位置的方法。

此方法执行的操作取决于从选择器中检索到的值。最初我向 useEffect 传递了一个空的依赖项数组,因此它只会在挂载时添加事件监听器。然而,显然这会导致围绕选择器值的陈旧闭包。一个可行的解决方案是将选择器作为依赖项传递给它——但是,这会导致每次选择器的值发生变化时都会删除/重新添加监听器,这不是很好。

我正在尝试考虑一种解决方案,它只添加一次事件监听器,同时允许被调用的方法访问选择器的当前值。

示例代码:

const currentValue = useSelector(state => getValue(state));

useEffect(() => {
document.addEventListener('my.custom.event', handleEvent);

return(() => document.removeEventListener('my.custom.event', handleEvent));
}, []);

const handleEvent = () => {
console.log(currentValue)
}

照原样,这会围绕 currentValue 创建一个陈旧的闭包,因此在事件触发时,记录的值不一定是最新的。

useEffect 中将 [] 更改为 [currentValue] 会导致预期的行为,但会删除/重新添加事件监听器currentValue 的变化。

由于这不是组件的状态值,因此无法使用类似 console.log(currentValue => console.log(currentValue)) 的回调来访问最新值.我也尝试过使用 useRef 来保留该值,但我相信每次选择器的值发生变化时我都需要某种方法来更新 ref 值,这不是一个很好的解决方案。

在实际组件中,currentValue 的值在 Redux 中被其他组件修改,因此将其更改为状态值也不太可行。

我在想:

  • 是否有刷新被调用方法中选择器值的解决方案;
  • 是否唯一的解决方案是在依赖项发生变化时删除/重新添加监听器,或者;
  • 是否最好将此组件保留为类组件并完全绕过此问题(componentDidMount 不会遇到陈旧的关闭问题。)

最佳答案

useRef 方法通常是这个问题的解决方案,但您需要另一个 useEffect 来使用 currentValue 更新 ref:

const currentValue = useSelector(state => getValue(state));
const valueRef = useRef();

useEffect(() => { valueRef.current = currentValue; }, [currentValue]);

useEffect(() => {
const handleEvent = () => {
console.log(valueRef.current)
}

document.addEventListener('my.custom.event', handleEvent);

return(() => document.removeEventListener('my.custom.event', handleEvent));
}, []);

但是,您也可以从 useEffect 中提取整个函数,并在钩子(Hook)中使用它,这样您就可以轻松地为事件处理创建自定义钩子(Hook):

const useEventHandler = (eventName, eventHandler, eventTarget = document) => {
const eventHandlerRef = useRef();

useEffect(() => {
eventHandlerRef.current = eventHandler;
});

useEffect(() => {
const handleEvent = (...args) => eventHandlerRef?.current(...args);

eventTarget.addEventListener(eventName, handleEvent);

return (() => eventTarget.removeEventListener(eventName, handleEvent));
}, []);
}

使用钩子(Hook):

const currentValue = useSelector(state => getValue(state));

useEventHandler('my.custom.event', () => console.log(currentValue))

关于javascript - React/Redux、useEffect/useSelector、陈旧的闭包和事件监听器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71277021/

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