React useEffect钩子和Async/await自有fetch数据函数?

9

我尝试创建一个从服务器获取数据的函数,它可以工作。但是我不确定这是否正确的方法?

我创建了一个使用useStateuseEffectAsync/Await的函数组件来获取数据:

import React, { useState, useEffect } from "react";

const Fetch = () => {
  const [data, setData] = useState(null);
  useEffect(() => {
    const fetchData = async () => {
      let res = await fetch(
        "https://api.coindesk.com/v1/bpi/currentprice.json" //example and simple data
      );
      let response = await res.json();
      setData(response.disclaimer); // parse json
      console.log(response);
    };
    fetchData();
  }, []);
  return <div>{data}</div>;
};

export default Fetch; // don't run code snippet, not working, this component must be imported in main

我不确定的地方是在哪里调用fetchData函数。我应该在useEffect内部调用它吗?这样做是正确的吗?而且,这个调用只会发生一次吗?因为我使用了[]?

通常,你会如何处理这样的情况?


1
你的代码看起来没问题。是的,你可以在 useEffect 中这样做。是的,这只会发生一次,因为你使用了 [ ] - Nicholas Tower
好的,正确的位置在下面的函数中调用她? - Milosh N.
是的,由于空数组,调用只会在组件装载时发生。第二个参数中的数组指定钩子要观察哪些变化,只有当这些依赖项中的任何一个发生更改时才应用效果。传入一个空值告诉钩子,您的组件不依赖于props / state,因此将仅在组件装载上应用该钩子。 - Thulani Chivandikwa
2个回答

11

总的来说,你正在朝着正确的方向前进。为了获取数据,你应该使用useEffect并将[]作为第二个参数传递以确保它仅在初始挂载时触发。

我认为你可以从解耦fetchJson函数并使其更通用中受益,如下所示:

const fetchJson = async (url) => {
  const response = await fetch(url);
  return response.json();
};

const Fetch = () => {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetchJson("https://api.coindesk.com/v1/bpi/currentprice.json")
      .then(({ disclaimer }) => setData(disclaimer));
  }, []);

  return <div>{data}</div>;
};

1
在这个例子中,你需要等待fetchData调用或者使用.then。除非我遗漏了什么? - Thulani Chivandikwa
1
另外,我不明白这样做的原理,因为你不能在非异步函数中使用await,对吧?所以await fetchData是无效的。 - adam-beck
1
我对Hooks还很陌生,但是您需要使用setData(disclaimer)而不是setState(disclaimer)吗? - Syl OR

7

另一个选项是使用自执行函数:

const Fetch = () => {
  const [data, setData] = useState(null);
  useEffect(() => {
    (async () => {
      let res = await fetch(
        "https://api.coindesk.com/v1/bpi/currentprice.json" //example and simple data
      );
      let response = await res.json();
      setData(response);
    })();
  }, []);
  return <div>{data}</div>;
};

将获取逻辑分离到单独的函数中是个好主意,可以按照以下方式完成:

const Fetch = () => {
  const [data, setData] = useState(null);
  useEffect(() => {
    (async () => {
      let response= await fetchData("https://api.coindesk.com/v1/bpi/currentprice.json");
      setData(response);
    })();
  }, []);
  return <div>{data}</div>;
};

const fetchData = async (url) => {
  const response = await fetch(url);
  const json = await response.json();

  return json;
};

还有另一种选择,就是创建一个包装函数来触发异步函数,类似于以下代码:

export function useAsyncEffect(effect: () => Promise<any>) {
  useEffect(() => {
    effect().catch(e => console.warn("useAsyncEffect error", e));
  });
}

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