[英]async function triggers setstate before await is complete
在获取所有数据之前调用 setLoading。 如何确保仅在获取数据的 for 循环完成后才调用 setLoading? 将异步数据与非异步数据结合起来甚至是可取的吗? 我想要实现的是呈现一个时间线,每个事件都伴随着它们各自的方向(这是异步数据)
const Schedule = (props) => {
const [events, setEvents] = React.useState([]);
const [visible, setVisible] = React.useState(false);
const [unsatisfied, setUnsatisfied] = React.useState("");
const [timingsArray, setTimingsArray] = React.useState([]);
const [isLoading, setLoading] = React.useState(true);
React.useEffect(() => {
directionsArray(props.initRoutes, props.timings, props.data);
}, []);
const directionsArray = async (allRoutes, timings, data) => {
let result = [];
for (let i = 0; i < allRoutes.length - 1; i++) {
let obj = { distance: "", duration: "", steps: [] };
let steps = [];
let distance = "";
let duration = "";
let origin =
typeof allRoutes[i] === "object"
? allRoutes[i].lat + "," + allRoutes[i].long
: allRoutes[i];
let destination = allRoutes[i + 1];
try {
let resp = await fetch(
"https://maps.googleapis.com/maps/api/directions/json?origin=" +
origin +
"&destination=" +
destination +
"&key=" +
GOOGLE_MAPS_API_KEY +
"&mode=transit®ion=sg"
);
//console.log(JSON.stringify(await resp.json()));
let data = (await resp.json())["routes"][0]["legs"][0];
let response = data["steps"];
distance = data["distance"]["text"];
duration = data["duration"]["text"];
for (let j = 0; j < response.length; j++) {
steps.push(await routeFormatter(await response[j]));
}
} catch (err) {
console.log(err);
}
obj.steps = steps;
obj.distance = distance;
obj.duration = duration;
result.push(obj);
}
let updatedTimings = merge(timings, result);
let combinedData = eventsWithDirections(updatedTimings, data, result);
setTimingsArray(updatedTimings);
setEvents(combinedData);
setLoading(false);
};
if (isLoading) {
return (
<View
style={{
flex: 1,
alignContent: "center",
justifyContent: "center",
}}
>
<ActivityIndicator
style={{ alignSelf: "center" }}
size="large"
/>
</View>
);
} else {
return (
<View style={styles.container}>
<View style={styles.body}>
<Modal animated visible={visible} animationType="fade">
<ActionOptions
onReselect={onReselect}
onClose={onClose}
unsatisfied={unsatisfied}
events={props.allEvents}
genres={props.genres}
newTimeChange={newTimeChange}
filters={props.filters}
/>
</Modal>
<Timeline
onEventPress={(event) => onEventPress(event)}
data={events}
timeStyle={{
textAlign: "center",
backgroundColor: "#cc5327",
color: "white",
padding: 5,
borderRadius: 13,
}}
/>
</View>
<View style={styles.footer}>{renderProceedButton()}</View>
</View>
);
}
};
我相信这里的问题是遍历allRoutes
的循环需要包装在Promise.all
中。 现在,在循环的每次迭代中, try
块中代码的 rest 将等待获取数据,但setLoading
在 scope 之外被调用,并且没有被告知await
其他任何内容。
而不是 for 循环,也许尝试让迭代类似于
await Promise.all(allRoutes.map( (route) => {
//code that's currently in the for loop
}))
希望这是有道理的。 我发现这篇文章对主题也很有帮助: https://zellwk.com/blog/async-await-in-loops/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.