更新代码后仅 Promise.All 的异步函数 运行

Async Function with Promise.All Only Running After Updating Code

我正在 React 中编写一个异步函数,它应该将“坐标”状态设置为包含美国各州及其各自 latitudes/longitudes 的对象数组。为此,我进行了 API 调用并使用 Promise.all 解析这些调用。在页面的第一次刷新时,该功能按预期工作。但是,在随后的刷新中,该函数不会执行 Promise.all 语句,因此不会设置坐标状态。为什么会这样,我该如何解决这个问题?

export default function App() {

  const [covidDataJSON, setCovidDataJSON] = useState(null);
  const [stateNames, setStateNames] = useState([]);
  const [coords, setCoords] = useState([]);
  const [stateInfos, setStateInfos] = useState([]);

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

  const fetchCoords = async () => {
    try {
      getStateNames();
      const req = await Promise.all(stateNames.map(async (state) => {
        return await axios.get(`https://nominatim.geocoding.ai/search.php?state=${state}&format=jsonv2`);
      }))
      for (let i = 0; i < req.length; i++){
        const stateInfo = req[i].data[0];
        if (req[i].data.length !== 0)
          setCoords(coordsArr => [...coordsArr, {name: stateInfo.display_name, lat: stateInfo.lat, lon: stateInfo.lon}]);
      }
    } catch (err) {
      console.error(err);
    }
  };

  const getStateNames = () => {
    try {
      const stateArr = [];
      for (let i = 0; i < states.length; i++){
        stateArr.push(states[i].name);
      }
      setStateNames(stateArr);
    } catch (error) {
      console.error(error);
    }
  }

我认为你的 promise.all 没有执行,因为 stateNames 仍然是一个空数组。

您需要定义2个useEffect hooks如下。 -

// this will trigger function fetchCoords once your have set the stateNames.
useEffect(() => {
    if(!stateNames || !stateNames.length){
        return;
    }
    fetchCoords();
}, [stateNames]);

// this hook will set your stateNames once the component loads.
useEffect(() => {
    getStateNames();
}, [])

此外,我没有看到上面示例代码中定义的 getStateNames 中使用的状态变量。同时从 fetchCoords() 内部删除 getStateNames() 调用让我知道以上是否适合您,并尝试记录 stateNames 以验证这一点。

  1. getStateNames() 中,您正在调用 setStateNames(stateArr); setter 函数,因为状态是异步的。您正在映射 fetchCoords() 内的 stateNames。当地图循环为 运行 时,有可能 stateNamesstate 未更新。这就是为什么我从 getStateNames() return stateArr 并在 fetchCoords().

    中使用该值
  2. fetchCoords() 中,您添加了以下代码


const req = await Promise.all(stateNames.map(async (state) => {
        return await axios.get(`https://nominatim.geocoding.ai/search.php?state=${state}&format=jsonv2`);
      }))

这里不需要 await axios.get() 因为你已经在使用 Promise.all 来等待 promises 解决,这就是我从 [=23= 中删除 await axios.get() 的原因] 并简单地 return 对 Promise.all()

的一系列承诺

试一试。我认为这应该有效。


export default function App() {
  const [covidDataJSON, setCovidDataJSON] = useState(null);
  const [stateNames, setStateNames] = useState([]);
  const [coords, setCoords] = useState([]);
  const [stateInfos, setStateInfos] = useState([]);

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

  const fetchCoords = async () => {
    try {
      const stateArr = getStateNames();
      const req = await Promise.all(
        stateArr.map((state) => {
          return axios.get(
            `https://nominatim.geocoding.ai/search.php?state=${state}&format=jsonv2`
          );
        })
      );

      for (let i = 0; i < req.length; i++) {
        const stateInfo = req[i].data[0];
        if (req[i].data.length !== 0)
          setCoords((coordsArr) => [
            ...coordsArr,
            {
              name: stateInfo.display_name,
              lat: stateInfo.lat,
              lon: stateInfo.lon
            }
          ]);
      }
    } catch (err) {
      console.error(err);
    }
  };

  const getStateNames = () => {
    try {
      const stateArr = [];
      for (let i = 0; i < states.length; i++) {
        stateArr.push(states[i].name);
      }
      setStateNames(stateArr);
      return stateArr;
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}