【问题标题】:Passing down async fetched data via Context API通过 Context API 传递异步获取的数据
【发布时间】:2020-06-27 21:06:12
【问题描述】:

数据未显示在子组件Store 中。在Store组件中,useEffect()钩子中的console.log返回undefined。我怀疑原因是父组件中的fetchAPI 函数仅在渲染myContext.Provider 后调用,因此myContext.Providervalue 未定义。

在这种情况下,如何将我从 Stores(parent) 中的 API 获取的 data(hook state) 传递给 Store(child)?

export const myContext = createContext()


const Stores = () =>{

    const [data, setData ] = useState([])


    const fetchAPI = async() => {
        var res = await fetch('https://fortnite-api.theapinetwork.com/store/get')
        var result = await res.json()
        var final= result.map(item => item)
        setData(final)
    }

    useEffect(() =>{
        fetchAPI().then(console.log(data))
    }, [data])

    return(
        <div>
         <myContext.Provider value={data} > 
            {data.map(item => {
                return(
                <div>
                    <ul>
                        <Link to={`stores/${item.itemId}`}><li>{item.item.name}</li></Link>
                    </ul>
                </div>
                )
            })}
          </myContext.Provider>
        </div>
    )
};

const Store = () => {

    const specific = useContext(myContext)

    useEffect(
        () => {
            console.log(specific)
        }

    )
    
    return(
    <>
    {specific.map( item => {
        return(
        <div>
            <h2> Description: {item.name}</h2>
        </div>
        )
    })}
    </>
    )
}

【问题讨论】:

  • 首先,then 需要一个函数,但您将控制台日志的结果传递给它,这是未定义的,因为控制台日志不返回任何内容。您没有看到数据被填充的原因是该组件尚未重新渲染。您正在关闭 data 变量,在关闭时它是一个空数组。您还将有一个无限循环,因为每次数据更改时您都会调用 fetch,并且您在 fetch 中设置数据。

标签: reactjs react-router react-hooks react-context


【解决方案1】:

我认为您使用 fetch api 的方式不正确。 fetch 返回一个promise,所以如果你想使用.then(),你需要在你的fetchAPI 方法中返回这个promise。

.then() 允许你抓住承诺并使用它,这里是你的代码更改为工作:

import React, { Component, useState, useEffect, createContext } from "react";
import { render } from "react-dom";

const myContext = createContext()

const App = () =>{

    const [data, setData ] = useState([]);


    const fetchAPI = () => {
      // It return a promise
       return fetch('https://fortnite-api.theapinetwork.com/store/get');
    }

    useEffect(() =>{
        fetchAPI().then(data => 
        // try to call .json() method. this method returns a promise
          data.json().then(json => {
            // if .json() succeed, then do your stuff
            console.log(json);
            setData(json.data.map(item => item));
          })
        )
        // if .json() fails, promise is rejected with your error
        .then(err => console.log('err', err));
    }, []); // empty array to prevent looping (rule : do not update a state you are passing in this deps array)

    return(
        <div>
         <myContext.Provider value={data} > 
            {data.map(item => {
                return(
                <div>
                    <ul>
                        <li><pre>{JSON.stringify(item)}</pre></li>
                    </ul>
                </div>
                )
            })}
          </myContext.Provider>
        </div>
    )
};

render(<App />, document.getElementById("root"));

这里是the repro on Stackblitz

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-02
    • 1970-01-01
    • 2016-12-05
    • 2021-05-16
    • 2015-06-13
    • 2016-03-29
    • 2021-08-22
    • 2019-05-25
    相关资源
    最近更新 更多