如何在 useEffect 和 setState 中循环

How to loop in useEffect and setState

我有类别,每个类别都有子类别,我想设置一个像

这样的字典

{category1.name: [/*list of all subcategories*/], category2.name: [...]}

我有

useEffect(()=>{
        Axios.get("http://localhost:3001/categories/get").then((p) => { /* return a list of categories */
            setCategories(p.data)
            let actual = {}
            for (let i = 0; i < p.data.length; i++) {
                Axios.get("http://localhost:3001/category/subcategories", { /* return all the subcategories of p.data[i], this is working! */
                params : {category : p.data[i].category}}).then((p) => {
                    actual = {...actual, [p.data[i].category]: p.data}
                    console.log(actual) /* 1 */
                })
            }
            console.log(actual) /* 2 */
        })
    }, [])

我已经让后端工作了,但是当我 console.log(actual) /* 2 */ 它只是一个空字典 {};当我 console.log(actual) /* 1 */ 它不为空(只有 1 个元素)时,我不知道我什么时候可以 setState(actual),有人知道如何做我想做的事吗?

您只需使用 async/await 即可满足您的需求。

编辑(@skyboyer 提到):

当您进行网络调用时,所有请求将按顺序进行,加载需要 N×time_to_load_one

试试这个。

useEffect(()=>{
        Axios.get("http://localhost:3001/categories/get").then(async (p) => { /* return a list of categories */
            setCategories(p.data)
            let actual = {}
            for (let i = 0; i < p.data.length; i++) {
                await Axios.get("http://localhost:3001/category/subcategories", { /* return all the subcategories of p.data[i], this is working! */
                params : {category : p.data[i].category}}).then((p) => {
                    actual = {...actual, [p.data[i].category]: p.data}
                    console.log(actual) /* 1 */
                })
            }
            console.log(actual) /* 2 */
        })
    }, [])

这应该能让您走上正轨

useEffect(() => {
    (async() => {
        const p = await Axios.get("http://localhost:3001/categories/get")
        setCategories(p.data)
        let actual = {}
        for (let i = 0; i < p.data.length; i++) {
            const x = await Axios.get("http://localhost:3001/category/subcategories", { /* return all the subcategories of p.data[i], this is working! */
                params: {
                    category: p.data[i].category
                }
            })

            actual = {...actual, [x.data[i].category]: x.data
            }
            console.log(actual) /* 1 */

        }
        console.log(actual) /* 2 */
    })();
}, [])

同时避免重复使用与 p 相同的变量,这会使阅读代码变得更加困难。

在我看来,你需要花时间学习JS中的promiseasync/await。原谅我不能花时间写一整篇文章来教大家,请google这些关键词。

为了补充使用 async/await 的 ,下面是一个使用 promise 的解决方案。他的解决方案是按顺序发出请求,而我的是同时发出请求。

useEffect(() => {
    Axios.get("http://localhost:3001/categories/get").then((p) => {
        /* return a list of categories */
        setCategories(p.data)

        const tasks = p.data.map((category) => {
            return Axios.get(
                "http://localhost:3001/category/subcategories",
                { params: { category } }
            ).then((p) => {
                return { [category]: p.data }
            })
        })
        
        Promise.all(tasks).then(results => {
            const actual = results.reduce((acc, item) => {
                return { ...acc, ...item }
            }, {})
        })

        setState(actual)
    })
}, [])