开发者问题收集

如何在 useEffect 中设置状态完成后调用函数?

2021-02-12
2917

我希望仅当 customEffect 完成设置 isReady 状态时才运行 customFunction 。并且,无论 isReady 设置为 false 还是 true ,只要在设置后运行, customFunction 都应只运行一次。

import customFunction from 'myFile';

export const smallComponent = () => {
  const [isReady, setIsReady] = useState(false);

  useEffect(() => {
    const customEffect = async () => {
      try {
        const response = await get(
          `some-api.com`,
        );
        return setIsReady(response); // response can be true or false
      } catch {
        return null;
      }
    };

    customEffect();

    customFunction();
  }, []);

  return (
    <>Hello World</>
  )

}


我尝试添加 isReady 作为第二个 useEffect 参数,但我的 customFunction 在 customEffect 完成之前运行,然后在设置 isReady 之后再次运行。

还尝试使用单独的 useEffect,但似乎仍然在 customEffect 完成之前运行。

3个回答

将初始值设置为 null 并使用单独的 useEffect ,正如 Kevin 所建议的(仅不检查 isReady true/false)。

在这种情况下, setIsReady 会将 isReady 从 null 更改为 true/false,并且将调用第二个 useEffect

import customFunction from 'myFile';

export const smallComponent = () => {
    const [isReady, setIsReady] = useState(null);

    useEffect(() => {
        const customEffect = async () => {
            try {
                const response = await get(
                    `some-api.com`,
                );
                return setIsReady(response);
            } catch {
                return null;
            }
        };

        customEffect();
    }, []);

    useEffect(() => {
       if (null === isReady) {
          return;
       }
       customFunction();
    }, [isReady]);

    return (
        <>Hello World</>
    )
}
p1uton
2021-02-12

由于您想要提示效果在 设置 isReady 状态后 运行,并且 isReady 的值无关紧要,因此您可以使用第二个状态值来指示第一个效果和状态更新已完成。

这将触发第二个效果以调用 customFunction ,但您不希望您的组件保持此状态,因为从现在起,任何时候组件重新渲染,条件仍将得到满足。您需要第三个“状态”来指示第二个效果已触发。在这里,您可以使用 React ref 来指示这一点。

export const smallComponent = () => {
  const [readySet, setReadySet] = useState(false);
  const [isReady, setIsReady] = useState(false);
  const customFunctionRunRef = useRef(false);

  useEffect(() => {
    const customEffect = async () => {
      try {
        const response = await get(
          `some-api.com`,
        );

        setReadySet(true); // to trigger second effect callback
        return setIsReady(response); // response can be true or false
      } catch {
        return null;
      }
    };

    customEffect();
  }, []);

  useEffect(() => {
    if (readySet && !customFunctionRunRef.current) {
      // won't run before readySet is true
      // won't run after customFunctionRunRef true
      customFunction();
      customFunctionRunRef.current = true;
    }
  }, [readySet]);

  return (
    <>Hello World</>
  );
}

从 @p1uton 借来的更好的解决方案。使用 null isReady 状态来指示 customFunction 不应调用,并使用 ref 来阻止其在之后被调用。

export const smallComponent = () => {
  const [isReady, setIsReady] = useState(null);
  const customFunctionRunRef = useRef(false);

  useEffect(() => {
    const customEffect = async () => {
      try {
        const response = await get(
          `some-api.com`,
        );

        return setIsReady(response); // response can be true or false
      } catch {
        return null;
      }
    };

    customEffect();
  }, []);

  useEffect(() => {
    if (isReady !== null && !customFunctionRunRef.current) {
      // won't run before isReady is non-null
      // won't run after customFunctionRunRef true
      customFunction();
      customFunctionRunRef.current = true;
    }
  }, [isReady]);

  return (
    <>Hello World</>
  );
}
Drew Reese
2021-02-12

我不确定我是否理解正确,但这就是我使用单独的 useEffect 的方式。

import customFunction from 'myFile';

export const smallComponent = () => {
    const [isReady, setIsReady] = useState(false);

    useEffect(() => {
        const customEffect = async () => {
            try {
                const response = await get(
                    `some-api.com`,
                );
                return setIsReady(response);
            } catch {
                return null;
            }
        };

        customEffect();
    }, []);

    useEffect(() => {
        if (!isReady) {
            return;
        }

        customFunction();
    }, [isReady]);

    return (
        <>Hello World</>
    )
}
Kevin Sandow
2021-02-12