我有一个简单的对话框组件,它采用
open
属性来控制是否显示对话框,以及 onOpen
属性,它是每次对话框打开时运行的回调。
我可以像这样非常简单地实现这一点:
const MyDialog = ({ open, onOpen, children }) => {
React.useEffect(() => {
if (open) {
onOpen()
}
}, [open])
// The dialog that gets rendered uses a UI library’s dialog component.
return (
<UnderlyingDialogComponent open={open}>
{children}
</UnderlyingDialogComponent>
)
}
这工作得很好,除了
react-hooks/exhaustive-deps
linting 规则(来自 eslint-plugin-react-hooks)告诉我,我需要在 onOpen
的依赖项数组中包含 useEffect
。
但是,如果我这样做,那么每当
onOpen
回调发生变化时,也会调用 onOpen
回调,这不是我想要的行为。我希望仅当 open
属性从 false
更改为 true
时才调用它。
有没有一种简单的方法可以做到这一点,而无需禁用 linting 规则?或者在这种情况下我可以忽略所有依赖项必须包含在依赖项数组中的“规则”?
编辑:我知道如果
onOpen
处理程序是使用 useCallback
制作的,那么它不应该改变,但我不能保证该组件的任何用户都会这样做。我希望我的组件能够正确运行,无论用户是否使用 useCallback
作为他们的 onOpen
处理程序。
您可以考虑使用自定义挂钩,
useEffectEvent
来帮助您处理此问题。 React 目前正在试验这样的功能,所以你也可以使用以下命令导入它:
import { experimental_useEffectEvent as useEffectEvent } from 'react';
或者,您可以创建类似的东西并自己维护:
function useMyEffectEvent(handler) {
const handlerRef = useRef(null);
useLayoutEffect(() => {
handlerRef.current = handler;
});
return useCallback((...args) => {
const fn = handlerRef.current;
return fn(...args);
}, []);
}
此挂钩将在所有重新渲染中返回稳定的函数引用,因此不需要将其包含在依赖项数组中。它还具有始终调用“最新”
onOpen
函数的额外优点,避免该回调中潜在的陈旧关闭问题。 MyDialog
组件,您可以创建参考:
const MyDialog = ({ open, onOpen, children }) => {
const onOpenHandler = useMyEffectEvent(onOpen);
React.useEffect(() => {
if (open) {
onOpenHandler();
}
}, [open]);
...
}
请密切注意当前的限制以及从该钩子返回的回调。另外,如果您首先需要此处的效果,则值得考虑。例如,如果您的内部对话框有一个可以点击的 onOpen 事件,因为使用它会更好。