簡體   English   中英

React 鈎子函數依賴

[英]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
}

解決方案1。

對您來說,最簡單的技術是將新計算的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]);

解決方案 2。

另一種技術可以在這里找到: https : useEffect正在使用useEffectsetBarfoo的依賴項列表。

React.useEffect(() => {
    setFoo(getFoo(props.fooList, props.fooId));
}, [props.fooId]);

React.useEffect(() => {
    setBar(getBar(foo.listToFilter));
}, [foo]);

盡管答案獲得了 27 票,但我認為這只是使情況過於復雜,而且(據我所知)使組件不必要地重新渲染 2 次而不是 1,應該避免。


解決方案 3。

另一個可能有效的解決方案是使用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]);

你看,工作代碼又是另一個過於復雜(和糟糕)的解決方案,(但無論如何都應該引入??)。


解決方案 4。

gaearon提到的另一個解決方案是使用useReducer

  • 使用 Hooks,您還可以使用 Reducer 來集中狀態更新邏輯並避免這個陷阱。

他的另一個見解:

  • 推薦的解決方案是使用一個變量而不是兩個變量(因為一個變量似乎可以從另一個變量計算出來),或者先計算下一個值,然后一起使用它來更新它們。 或者,如果您准備好進行跳躍,useReducer 有助於避免這些陷阱。

但這似乎又是對本案的另一個過於復雜的建議,不是嗎?


解決方案 5。

最后一個建議是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM