繁体   English   中英

异步 function 在等待完成之前触发 setstate

[英]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&region=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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM