更新代码后仅 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 以验证这一点。
在 getStateNames()
中,您正在调用 setStateNames(stateArr);
setter 函数,因为状态是异步的。您正在映射 fetchCoords()
内的 stateNames。当地图循环为 运行 时,有可能 stateNames
state 未更新。这就是为什么我从 getStateNames()
return stateArr
并在 fetchCoords()
.
中使用该值
在 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>
);
}
我正在 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 以验证这一点。
在
中使用该值getStateNames()
中,您正在调用setStateNames(stateArr);
setter 函数,因为状态是异步的。您正在映射fetchCoords()
内的 stateNames。当地图循环为 运行 时,有可能stateNames
state 未更新。这就是为什么我从getStateNames()
returnstateArr
并在fetchCoords()
.在
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>
);
}