我应该如何删除警告 "React Hook useEffect has a missing dependency"?
How should i remove warning "React Hook useEffect has a missing dependency"?
我有一个函数在 useEffect
中使用并单击事件,然后抛出警告 "React Hook useEffect has a missing dependency",我应该如何删除警告?
// location is react router location
const Component = ({ location }) => {
const [data, setData] = useState(null);
const fetchData = () => {
const { id } = parseLocation(location);
fetchDataFromServer(id).then(data => setData(data));
}
useEffect(() => {
fetchData();
}, [location]);
return (
<div>
{data}
<button onClick={fetchData)}>reload</button>
</div>
);
}
然后我试试这个,但是警告仍然存在
// location is react router location
const Component = ({ location }) => {
const [data, setData] = useState(null);
const fetchData = (l) => {
// l is location
const { id } = parseLocation(l);
fetchDataFromServer(id).then(data => setData(data));
}
useEffect(() => {
fetchData(location);
}, [location]);
return (
<div>
{data}
<button onClick={() => fetchData(location)}>reload</button>
</div>
);
}
exhaustive-deps
规则的要点是防止钩子读取陈旧的道具或状态。问题是,由于 fetchData
是在组件中定义的,就 linter 而言,它可能正在访问陈旧的 props
或状态(通过闭包)。
一个解决方案是将 fetchData
从组件中拉出并传递它所需的一切:(它已经传递了位置):
const fetchData = (l, setData) => {
// l is location
const { id } = parseLocation(l);
fetchDataFromServer(id).then(data => setData(data));
}
const Component = ({ location }) => {
const [data, setData] = useState(null);
useEffect(() => {
fetchData(location, setData);
}, [location]);
return (
<div>
{data}
<button onClick={() => fetchData(location, setData)}>reload</button>
</div>
);
}
由于 fetchData
没有在组件外部定义,linter 知道它不会访问状态或道具,所以这不是陈旧数据的问题。
需要明确的是,从 运行 时间的角度来看,您的原始解决方案是 正确的 ,因为 fetchData
不读取状态或道具- 但 linter 不知道这一点。
您可以简单地禁用 linter,但以后很容易不小心引入错误(如果曾经修改过 fetchData
)。最好让 linter 规则验证正确性,即使这意味着对代码进行一些轻微的重构。
备选方案
一种替代解决方案,它利用闭包而不是将位置传递给 fetchData
:
const Component = ({ location }) => {
const [data, setData] = useState(null);
const fetchData = useCallback(() => {
// Uses location from closure
const { id } = parseLocation(location);
fetchDataFromServer(id).then(data => setData(data));
// Ensure that location isn't stale
}, [location]);
useEffect(() => {
fetchData();
// Ensure that fetchData isn't stale
}, [fetchData]);
return (
<div>
{data}
<button onClick={fetchData}>reload</button>
</div>
);
}
这种方法可以避免每次调用时都将 location
传递给 fetchData
。但是,使用这种方法,重要的是要确保避免陈旧的状态和道具。
如果省略 [fetchData]
到 useEffect
的依赖,效果只会 运行 一次,并且 location
更改时不会获取新数据。
但是,如果您在 useEffect
的 deps 中有 fetchData
,但不将 fetchData
包装在 useCallback
中,则 fetchData
函数是一个新函数每个渲染都起作用,这会导致每个渲染 useEffect
到 运行(这很糟糕)。
通过包装在 useCallback
中,只要 location
发生变化,fetchData
函数就只是一个新函数,这会导致 useEffect
变为 运行合适的点。
我有一个函数在 useEffect
中使用并单击事件,然后抛出警告 "React Hook useEffect has a missing dependency",我应该如何删除警告?
// location is react router location
const Component = ({ location }) => {
const [data, setData] = useState(null);
const fetchData = () => {
const { id } = parseLocation(location);
fetchDataFromServer(id).then(data => setData(data));
}
useEffect(() => {
fetchData();
}, [location]);
return (
<div>
{data}
<button onClick={fetchData)}>reload</button>
</div>
);
}
然后我试试这个,但是警告仍然存在
// location is react router location
const Component = ({ location }) => {
const [data, setData] = useState(null);
const fetchData = (l) => {
// l is location
const { id } = parseLocation(l);
fetchDataFromServer(id).then(data => setData(data));
}
useEffect(() => {
fetchData(location);
}, [location]);
return (
<div>
{data}
<button onClick={() => fetchData(location)}>reload</button>
</div>
);
}
exhaustive-deps
规则的要点是防止钩子读取陈旧的道具或状态。问题是,由于 fetchData
是在组件中定义的,就 linter 而言,它可能正在访问陈旧的 props
或状态(通过闭包)。
一个解决方案是将 fetchData
从组件中拉出并传递它所需的一切:(它已经传递了位置):
const fetchData = (l, setData) => {
// l is location
const { id } = parseLocation(l);
fetchDataFromServer(id).then(data => setData(data));
}
const Component = ({ location }) => {
const [data, setData] = useState(null);
useEffect(() => {
fetchData(location, setData);
}, [location]);
return (
<div>
{data}
<button onClick={() => fetchData(location, setData)}>reload</button>
</div>
);
}
由于 fetchData
没有在组件外部定义,linter 知道它不会访问状态或道具,所以这不是陈旧数据的问题。
需要明确的是,从 运行 时间的角度来看,您的原始解决方案是 正确的 ,因为 fetchData
不读取状态或道具- 但 linter 不知道这一点。
您可以简单地禁用 linter,但以后很容易不小心引入错误(如果曾经修改过 fetchData
)。最好让 linter 规则验证正确性,即使这意味着对代码进行一些轻微的重构。
备选方案
一种替代解决方案,它利用闭包而不是将位置传递给 fetchData
:
const Component = ({ location }) => {
const [data, setData] = useState(null);
const fetchData = useCallback(() => {
// Uses location from closure
const { id } = parseLocation(location);
fetchDataFromServer(id).then(data => setData(data));
// Ensure that location isn't stale
}, [location]);
useEffect(() => {
fetchData();
// Ensure that fetchData isn't stale
}, [fetchData]);
return (
<div>
{data}
<button onClick={fetchData}>reload</button>
</div>
);
}
这种方法可以避免每次调用时都将 location
传递给 fetchData
。但是,使用这种方法,重要的是要确保避免陈旧的状态和道具。
如果省略 [fetchData]
到 useEffect
的依赖,效果只会 运行 一次,并且 location
更改时不会获取新数据。
但是,如果您在 useEffect
的 deps 中有 fetchData
,但不将 fetchData
包装在 useCallback
中,则 fetchData
函数是一个新函数每个渲染都起作用,这会导致每个渲染 useEffect
到 运行(这很糟糕)。
通过包装在 useCallback
中,只要 location
发生变化,fetchData
函数就只是一个新函数,这会导致 useEffect
变为 运行合适的点。