关于此还有其他一些SO问题,答案要么是通过ESLint消除依赖项投诉(我正在使用打字稿),要么要做其他事情以仍然将useEffect的第二个参数设为[]
。但是,根据React relocation R_X86_64_32 against `.data' can not be used when making a shared object; recompile with -fPIC" libsshl.a,不建议这样做。同样在react useEffect文档下
如果传递一个空数组([]),则效果中的道具和状态 将始终具有其初始值。同时通过[]作为第二个 参数更接近熟悉的componentDidMount和 componentWillUnmount心智模型,通常有更好的解决方案 避免过于频繁地重新运行效果。另外,别忘了React 将useEffect推迟到浏览器绘制完毕后再进行,这样 多余的工作没什么问题。
我有以下代码:
useEffect(() => {
container.current = new VisTimeline(container.current, items, groups, options);
}, [groups, items, options]);
我希望它只运行一次。
绕过它的唯一方法是让它每次都运行,并且useState
跟踪它是否已经像这样运行过:
const [didLoad, setDidLoad] = useState<boolean>(false);
useEffect(() => {
if (!didLoad) {
container.current = new VisTimeline(container.current, items, groups, options);
setDidLoad(true);
}
}, [didLoad, groups, items, options]);
答案 0 :(得分:4)
我现在处理此问题的方法是将适当的依赖项放入依赖项列表中。
因为我只希望该效果只运行一次,并且由于该效果仅在组件首次安装时依赖于某些数据,所以可以忽略那些依赖关系。例如,groups
道具可能会在以后更改,但此效果无需再次运行。
但是,作为一种习惯,我不会忽略建议的依赖项,而是始终列出它们。如果我有意遗漏某些东西,我会添加一个eslint ignore语句(虽然还没有遇到需要这样做的事情)...只要您了解数据发生变化时正在发生的事情,就可以遵循任何约定。效果不起作用。
但是,如果您要列出依赖项,我提出的代码也不是最佳解决方案:
const [didLoad, setDidLoad] = useState<boolean>(false);
useEffect(() => {
if (!didLoad) {
container.current = new VisTimeline(container.current, items, groups, options);
setDidLoad(true);
}
}, [didLoad, groups, items, options]);
此效果运行时,我不想引起渲染。因此,我将使用ref(不需要是依赖项)来代替使用状态。
const timelineLoaded = useRef<boolean>(false);
useEffect(() => {
if (!timelineLoaded.current) {
container.current = new VisTimeline(container.current, items, groups, options);
timelineLoaded.current = true;
}
}, [groups, items, options]);
答案 1 :(得分:0)
useEffect(() => {
container.current = new VisTimeline(container.current, items, groups, options);
}, [groups, items, options]);
上面的代码每次在数组中的变量之一更改时就运行该函数。如果您只想运行一次,那么[]
应该是文档中提到的数组。所以基本上
useEffect(() => {
container.current = new VisTimeline(container.current, items, groups, options);
}, []);
希望这会有所帮助。
答案 2 :(得分:0)
添加额外的代码来解决工具问题并不好。
解决实际问题 - 在这种情况下,从 linter 中排除您知道以您想要的方式工作的代码。
在您知道不需要 useEffect
依赖项数组中的值的代码上特别禁用 linting。在 useEffect
代码块上方添加:
/* eslint-disable react-hooks/exhaustive-deps */
答案 3 :(得分:-1)
这个自定义钩子是 useEffect
上的一个包装器,只会在第一次渲染后运行并且不违反 react-hooks/exhaustive-deps
eslint 规则:
import { useEffect } from 'react';
const useEffectOnlyOnce = func => useEffect(func, []);
export default useEffectOnlyOnce;
可以这样使用:
import useEffectOnlyOnce from '<path-to-your-custom-hook>/useEffectOnlyOnce'
...
useEffectOnlyOnce(() => {
container.current = new VisTimeline(container.current, items, groups, options);
});
...
此解决方案来自 CSS Tricks 上的 comment 帖子