【问题标题】:How to loop in useEffect and setState如何循环使用 useEffect 和 setState
【发布时间】:2021-11-04 20:08:06
【问题描述】:

我有类别,每个类别都有子类别,我想 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),有人知道我想要做什么吗?

【问题讨论】:

  • 这里你需要使用promise,作为你的第二个控制台,即console.log(actual) /* 2 */在第一个控制台之前执行。所以它打印一个空对象。

标签: node.js reactjs use-effect setstate


【解决方案1】:

您可以使用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 */
        })
    }, [])

【讨论】:

  • 我认为值得一提的是,所有请求都会按顺序进行,加载需要 N×time_to_load_one
【解决方案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 那样重复使用相同的变量,这会使代码更难阅读。

【讨论】:

    【解决方案3】:

    在我看来,您需要花时间学习 JS 中的 promiseasync/await。请原谅我不能花时间写一整篇文章来教所有东西,请谷歌这些关键字。

    为了补充使用 async/await 的 @HarshPatel's answer,下面是使用 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)
        })
    }, [])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-04
      • 1970-01-01
      • 2021-11-27
      • 1970-01-01
      • 1970-01-01
      • 2020-08-02
      相关资源
      最近更新 更多