如何在 setState 更新 React 功能组件状态后立即正确执行逻辑?

How to properly execute logic right after setState updates the react functional component state?

目前,我正在制作一个个人资料页面,它最初将从 API 端点获取用户个人资料详细信息。我想要一个代表获取状态的加载指示器。我现在正在使用 useState 挂钩,我在其中存储 isLoading 状态的布尔值。但是,在阅读有关 useState 的文档后,它表示它可能是异步的。因此,如何先正确地将 isLoading 更新为 true 然后执行获取逻辑?现在这是我的代码片段。

function Profile() {
  const [isLoading, setIsLoading] = useState(false);
  const [user, setUser] = useState(null);
  const { username } = useParams();

  const fetchUserDetails = async (username) => {
    setIsLoading(true);
    try {
      const userRes = await API.graphql({
        query: queries.getUser,
        variables: { username },
      });
      if (userRes.error) {
        throw new Error({ cause: userRes.error });
      }
      setUser(userRes.data.getUser);
      setIsLoading(false);
    } catch (error) {
      console.error(error);
      // push to error page
      setIsLoading(false);
    }
  };

  // Fetch user profile data
  useEffect(() => {
    fetchUserDetails(username);
  }, []);

...

它的想法是在 fetch 函数中将初始的 isLoading 更新为 true,你做对了。缺少的是在 isLoading 为真时在 useEffect 中添加 if 条件,然后获取用户详细信息。

useEffect(() => {
 if(isLoading){
    fetchUserDetails(username);
 }
}, [isLoading])

只要条件为真,这就会进行提取。

在您的示例用例中,您最初可以简单地将 isLoading 设置为 true,然后 运行 您的挂载抓取。

function Profile() {
  const [isLoading, setIsLoading] = useState(true);
  const [user, setUser] = useState(null);
  const { username } = useParams();

  // Fetch user profile data
  useEffect(() => {
    const fetchUserDetails = async (username) => {
      try {
        const userRes = await API.graphql({
          query: queries.getUser,
          variables: { username },
        });
        if (userRes.error) {
          throw new Error({ cause: userRes.error });
        }
        setUser(userRes.data.getUser);
        setIsLoading(false);
      } catch (error) {
        console.error(error);
        // push to error page
        setIsLoading(false);
      }
    };

    fetchUserDetails(username);
  }, []);

但是如果你想观察 isLoading 的变化,比如说重新加载按钮,你可以先设置它 false,然后在挂载 useEffect 中将它设置为 true 并让你的 fetch useEffect 依赖于 isLoading

function Profile() {
  const [isLoading, setIsLoading] = useState(false);
  const [user, setUser] = useState(null);
  const { username } = useParams();

  // set isLoading to true on-mount
  useEffect(() => {
    setIsLoading(true)
  },[]);

  // Fetch user profile data
  useEffect(() => {
    const fetchUserDetails = async (username) => {
      try {
        const userRes = await API.graphql({
          query: queries.getUser,
          variables: { username },
        });
        if (userRes.error) {
          throw new Error({ cause: userRes.error });
        }
        setUser(userRes.data.getUser);
        setIsLoading(false);
      } catch (error) {
        console.error(error);
        // push to error page
        setIsLoading(false);
      }
    };

    if (isLoading) {
      fetchUserDetails(username);
    }
  }, [isLoading]);

  function triggerReload() {
    setIsLoading(true)
  }