[英]How should i remove warning “React Hook useEffect has a missing dependency”?
i have a function that use in useEffect
and click event, then throw warning "React Hook useEffect has a missing dependency", how should i remove the warning? 我有一个在
useEffect
和click事件中使用的函数,然后引发警告“ React Hook useEffect具有缺少的依赖项”,我应如何删除警告?
// 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>
);
}
then i try this, but the warning still exist 然后我尝试这个,但警告仍然存在
// 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>
);
}
The point of the exhaustive-deps
rule is to prevent hooks from reading stale props or state. exhaustive-deps
规则的目的是防止挂钩读取陈旧的道具或状态。 The issue is that since fetchData
is defined within the component, as far as the linter is concerned, it could be accessing stale props
or state (via closure). 问题在于,由于
fetchData
是在组件内定义的,就fetchData
而言,它可能正在访问过时的props
或状态(通过闭包)。
One solution is to pull fetchData
out of the component and pass it everything it needs: (it's already being passed the location): 一种解决方案是将
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>
);
}
Since fetchData
isn't defined outside the component, the linter knows that it won't access state or props, so it isn't an issue for stale data. 由于
fetchData
不在组件外部定义,因此linter知道它不会访问状态或道具,因此对于陈旧数据而言这不是问题。
To be clear, though, your original solution is correct , from a runtime perspective, since fetchData
doesn't read state or props - but the linter doesn't know that. 不过要明确一点,从运行时的角度来看,您的原始解决方案是正确的 ,因为
fetchData
不会读取状态或fetchData
-但是fetchData
不知道。
You could simply disable the linter, but it'd be easy to accidentally introduce bugs later on (if fetchData
is ever modified) that way. 您可以简单地禁用linter,但是稍后以这种方式(如果曾经修改
fetchData
)不小心引入错误很容易。 It's better to have the linter rule verifying correctness, even if it means some slight restructuring of code. 最好使linter规则验证正确性,即使这意味着对代码进行一些轻微的重组。
An alternative solution which leverages closure instead of passing the location into fetchData
: 一种替代方法,该方法利用闭包而不是将位置传递到
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>
);
}
This approach lets you avoid passing location
into fetchData
every time you call it. 这种方法使您避免每次调用时都将
location
传递给fetchData
。 However, with this approach it's important to make sure to avoid stale state and props. 但是,使用这种方法时,务必确保避免过时的状态和道具。
If you omitted the [fetchData]
dep to useEffect
, the effect would only run once, and new data wouldn't be fetched when location
changed. 如果您将
[fetchData]
dep省略为useEffect
,则效果将仅运行一次,并且在location
更改时不会获取新数据。
But if you have fetchData
in the deps for useEffect
but don't wrap fetchData
in useCallback
, the fetchData
function is a new function every render, which would cause the useEffect
to run every render (which would be bad). 但是,如果您在
fetchData
的deps中有useEffect
但没有在useCallback
包装fetchData
,则fetchData
函数是每个渲染的新函数,这将导致useEffect
运行每个渲染(这很不好)。
By wrapping in useCallback
, the fetchData
function is only a new function whenever the location
changes, which causes the useEffect
to run at the appropriate point. 通过包装
useCallback
,只要location
发生变化, fetchData
函数就只是一个新函数,这会导致useEffect
在适当的位置运行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.