如何在状态改变后仅使用React的useEffect钩子一次?

6

我对React hooks很新,不确定如何实现以下目标。假设我有state1state2,我使用 useEffect hook 调用 asyncFn1 并更新 state1

现在我想等待state1改变,使用state1 值调用 asyncFn2,并更新state1state2。这个asnycFn1asyncFn2 应该只被调用一次。

如果我只是使用另一个useEffect来调用asyncFn2,我将无法获取state1的值。我该如何解决?

const [state1, setState1] = useState(null);
const [state2, setState2] = useState(null);

const asyncFn1 = async() => {
  // async call to get state 1 data
  // setState1
}

const asyncFn2 = async(_state1) => {
  // use state1 data to make async call to get state 2 data
  // state2 data will be used to update both state1 and state2
}

useEffect(() => {
  asyncFn1();
}, [])

你为什么想要从 asyncFn2 更新 state1asyncFn2 的输入 _state1 是否与你想要调用 setState1 的状态不同? - Patrick Roberts
1
参考 https://dev59.com/j1IH5IYBdhLWcg3weOYr#59492738,使用同样的逻辑,创建一个 ref 作为“仅调用一次”标志。 - Dennis Vash
@PatrickRoberts 是的,状态1会导致不同的asyncFn2结果,这将用于再次更新状态1。 - Orio Ryo
@DennisVash 谢谢!useRef 正是我所需要的。 - Orio Ryo
3个回答

9
你需要的是一个 useEffect,其中在 useEffect 依赖数组中包含你的 state1,以便于每当你的 state1 值改变时触发它,如下所示:
useEffect(() => {
   state1 && asyncFn2()
}, [state1])

如果您想让 asyncFn2 在获取state1的数据后只触发一次,您可以添加一个ref来检查何时调用它:

const dataLoaded = useRef(false)

useEffect(() => {
   if(state1 && !dataLoaded.current) {
      asyncFn2()
   }
}, [state1])

const asyncFn2 = async () => {
   // Your logic here

   // Set dataLoaded on true once you have updated what you need successfully
   dataLoaded.current = true
}

我看到你修复了你的示例,但我的陈述并没有错,之前你在useEffect中调用了useCallback,请尝试这段代码并告诉我你的发现。 - Dennis Vash
1
另外,应该使用!dataLoadedRef.current而不是!dataLoadedRef,因为后者总是一个真值语句。 - Dennis Vash
没错,这是个好观点,谢谢你指出来。但是你说的不要在函数内使用钩子,那函数组件怎么办呢? - ale917k
1
在React中,有“函数组件”,当说到“函数”时,那些只是JS函数,请参见https://reactjs.org/docs/hooks-rules.html“不要从常规JavaScript函数调用Hooks”。 - Dennis Vash

0

我经常这样做,发现对我来说最易读(和理解)的方法是使用一个钩子来存储某个东西的先前值。

export function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  }, [value]);
  return ref.current;
}

那么当我想在状态改变时仅创建一个特定副作用时,我会写:

const [fetching, setFetching] = useState(false);
const prevFetching = usePrevious(fetching);

useEffect(() => {
  if (prevFetching === true && fetching === false) {
    // Do something
  }
}, [fetching, prevFetching]);

0
要等待asyncFn1的结果来获取asyncFn2的数据,您可以在useEffect中使用IIFE,并等待asyncFn1完成执行并使用结果来调用asyncFn2。
useEffect(() => {
    (async function(){
      const result1 = await asyncFn1();
      // Use the result to fetch the data for asyncFn2 
      const result2 = await asyncFn2();
      // Update both state1 and state2
     })()
    }, [])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接