![](/img/trans.png)
[英]Eslint React Hooks Error: eslint-plugin-react-hooks exhaustive deps warning for a function dependency in useEffect
[英]React hooks function dependency
我發現自己處於一個奇怪的境地。 我正在實施一個鈎子,但我無法實現我想要的。
我有這樣的事情:
const appHook = props => {
const [foo, setFoo] = React.useState([]);
const [bar, setBar] = React.useState([]);
React.useEffect(() => {
setFoo(getFoo(props.fooList, props.fooId));
setBar(getBar(foo.listToFilter));
}, [props.fooId]);
const getCurrentBlockTrade = (arrayToFilter, number) =>
arrayToFilter.filter(array => array.id === number);
const getSubOutList = (...) => {
...
};
return (<div>something</div>)
}
我的問題是函數 setFoo 被正確執行,所以 foo state 是一個新數組,但取決於 foo 狀態的 setBar 接收一個空數組。 基本上 setBar 在 setFoo 完成之前執行,因此 getBar 函數接收一個空數組。
管理這種依賴的正確方法是什么?
謝謝,F。
TL; 博士; 您的解決方案可能是kind user
的回答
下面我將描述我迄今為止在整個研究中的想法和學到的東西,並從人們那里提出 5 條建議/解決方案,通過博客,...
你說過:
我的問題是函數 setFoo 被正確執行,所以 foo state 是一個新數組,但取決於 foo 狀態的 setBar 接收一個空數組。 基本上setBar 在 setFoo 完成之前執行,因此 getBar 函數接收一個空數組。
你是真的。 基本上是因為在 React(Hook 和類組件)中, setState
是異步的。 這是什么意思? 這意味着 setSomething 只是告訴 React稍后重新渲染組件。 它不會神奇地替換當前運行函數中的const something
變量——這是不可能的。
const [foo, setFoo] = useState(0)
function handleClick() {
setFoo(42)
// we declared foo with const, you "obviously" shouldn't expect this
// to "somehow" immediately change `foo` to 42
console.log(foo);
// it's 0 in this render, BUT on next render, `foo` will be 42
}
對您來說,最簡單的技術是將新計算的foo
值存儲在一個變量中,然后將該新計算的值用於 setFoo 和 setBar - 這是一種非常流行的技術。
React.useEffect(() => {
const newFoo = getFoo(props.fooList, props.fooId);
setFoo(newFoo);
setBar(getBar(newFoo.listToFilter));
}, [props.fooId]);
// or: shouldn't use this, only to demonstrate the callback syntax in
// the new setState Hook (different than the old callback syntax setState):
React.useEffect(() => {
setFoo(() => {
const newFoo = getFoo(props.fooList, props.fooId);
setBar(getBar(newFoo.listToFilter));
return newFoo;
})
}, [props.fooId]);
另一種技術可以在這里找到: https : useEffect
正在使用useEffect
來setBar
與foo
的依賴項列表。
React.useEffect(() => {
setFoo(getFoo(props.fooList, props.fooId));
}, [props.fooId]);
React.useEffect(() => {
setBar(getBar(foo.listToFilter));
}, [foo]);
盡管答案獲得了 27 票,但我認為這只是使情況過於復雜,而且(據我所知)使組件不必要地重新渲染 2 次而不是 1次,應該避免。
另一個可能有效的解決方案是使用async/await
使狀態更改異步觸發,以導致更改不被批處理(關於這個答案https://stackoverflow.com/a/53048903/9787887 )
React.useEffect(async () => {
await setFoo(getFoo(props.fooList, props.fooId));
await setBar(getBar(foo.listToFilter));
}, [props.fooId]);
// no, actually this will not work!! it'll throw you an (annoyed) error
// the actual working code is:
React.useEffect(() =>
const setFooAndBar = async () => {
await setFoo(getFoo(props.fooList, props.fooId));
await setBar(getBar(foo.listToFilter));
}
setFooAndBar();
}, [props.fooId]);
你看,工作代碼又是另一個過於復雜(和糟糕)的解決方案,(但無論如何都應該引入??)。
gaearon提到的另一個解決方案是使用useReducer
- 使用 Hooks,您還可以使用 Reducer 來集中狀態更新邏輯並避免這個陷阱。
他的另一個見解:
- 推薦的解決方案是使用一個變量而不是兩個變量(因為一個變量似乎可以從另一個變量計算出來),或者先計算下一個值,然后一起使用它來更新它們。 或者,如果您准備好進行跳躍,useReducer 有助於避免這些陷阱。
但這似乎又是對本案的另一個過於復雜的建議,不是嗎?
最后一個建議是gaearon的評論,告訴你重新思考你的狀態依賴,狀態依賴真的需要嗎?
最好的解決方案就是不要有從另一個狀態計算出來的狀態。 如果
this.state.y
總是從this.state.x
計算出來,this.state.y
完全刪除this.state.y
,只跟蹤this.state.x
。 並計算渲染時所需的內容
感謝您有足夠的耐心閱讀到這里:))。
setState
是一個異步函數,這就是您在setBar
函數中收到一個空數組的setBar
。 基本上你不能確定狀態會在第二個setState
評估之前更新。
為什么不在這兩種情況下都簡單地引用 props 呢?
React.useEffect(() => {
const newFoo = getFoo(props.fooList, props.fooId);
setFoo(newFoo);
setBar(getBar(newFoo.listToFilter));
}, [props.fooId]);
設置狀態是一個異步過程。 所以setBar(getBar(foo.listToFilter));
調用這個 foo 是空數組。 您可以為此使用另一個 useEffect
React.useEffect(() => {
setFoo(getFoo(props.fooList, props.fooId));
}, [props.fooId]);
React.useEffect(() => {
setBar(getBar(foo.listToFilter));
}, [foo]);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.