调用 REST API 并将其响应存储在 Context API 中

Posted

技术标签:

【中文标题】调用 REST API 并将其响应存储在 Context API 中【英文标题】:Call REST API and store its response in Context API 【发布时间】:2019-12-06 09:36:51 【问题描述】:

我的 React 应用程序要求将 API 驱动的数据存储在 Context API 中。类函数不仅仅是我们使用的函数组件。

我尝试使用 await 和 fetch 调用,但没有成功

const App = props => 
  const  initState  = props
  return (
    <AppContextProvider  initState=initState>
      <HoldingDetailsContainer initState=initState />
    </AppContextProvider>
  )


const AppContextProvider = (props) =>  
    const  resources  = useGetResourceApi();


    const context = 
        resources 
    ;
    return (
        <AppContext.Provider value=context>
            props.children
        </AppContext.Provider>
    )

如果我在 useGetResourceApi 前面使用 await ,那么它会抛出错误“对象作为 React 子级无效(找到:[object Promise])。如果您要渲染一组子级,请改用数组。 "

是否可以在上下文 API 中存储 API 驱动的数据

【问题讨论】:

useGetResourceApi 是自定义钩子吗? 这是一个自定义函数,内部做axios调用 【参考方案1】:

我看不到您的 API 调用或 HoldingDetailsContainer 的详细信息,也看不到您的导入,但下面是使用 Context API + Hooks + 函数组件获取的完整(人为)示例通过 REST API 获取数据并将其提供给组件:

// App.jsx

import React from "react";
import  APIContextProvider  from "./apiContext";
import Users from "./Users";

export default function App() 
  return (
    // wrap your app (or just components that need to consume the context)
    <APIContextProvider>
      <div className="App">
        <h1>Hello CodeSandbox</h1>
        // the Users component sits below the Provider so can consume its context
        <Users />
      </div>
    </APIContextProvider>
  );

// apiContext.jsx

import React,  useContext, useState, useEffect, createContext  from "react";
import axios from "axios";

const APIContext = createContext();

export function APIContextProvider( children ) 
  // for more complex state you might set up useReducer for Redux-like state updates
  const [users, setUsers] = useState([]);
  // useEffect is a lifecycle method for function components, run once after mount
  useEffect(() => 
    // the callback to useEffect can't be async, but you can declare async within
    async function fetchData() 
      // use the await keyword to grab the resolved promise value
      // remember: await can only be used within async functions!
      const  data  = await axios.get(
        `https://jsonplaceholder.typicode.com/users`
      );
      // update local state with the retrieved data 
      setUsers(data);
    
    // fetchData will only run once after mount as the deps array is empty 
    fetchData();
  , []);
  return (
    <APIContext.Provider
      // Add required values to the value prop within an object (my preference)
      value=
        users
      
    >
      children
    </APIContext.Provider>
  );


// Create a hook to use the APIContext, this is a Kent C. Dodds pattern
export function useAPI() 
  const context = useContext(APIContext);
  if (context === undefined) 
    throw new Error("Context must be used within a Provider");
  
  return context;

// 用户.jsx

import React from "react";
import  useAPI  from "./apiContext";

export default function Users() 
  // Now we can grab the data we want via useAPI, which abstracts useContext()
  const  users  = useAPI();
  return (
    <ul>
      // Now we can use the data from the API in our components
      // ofc this simple example can be adapted to make further calls
      users.map(u => (
        <li key=u.id>u.username</li>
      ))
    </ul>
  );

可以在我整理的这个沙箱中找到上述代码的工作、实时版本:https://codesandbox.io/s/context-api-fetch-data-provider-example-0rymy

【讨论】:

哇!我喜欢代码中的 cmets。它几乎感觉就像一个完整的教程。非常感谢!【参考方案2】:

请看这个要点:https://gist.github.com/nimahkh/9c008aaf2fd2d1cc83cd98c61e54979a

我认为你必须改变你的结构,在上下文中存储,就像存储在数据库或 redis 缓存中一样。 此外,在上下文中存储是一个异步过程,因此您必须获取 api,然后将其存储在上下文中。

我将通过我的要点示例向您展示代码

const App = () => 
    const initialState = 
        theme: primary: 'green'
    ;

    const reducer = (state, action) => 
        switch (action.type) 
            case 'storeApi':
                return 
                    ...state,
                    store_api: action.storeApi                ;

            default:
                return state;
        
    ;

    return (
        <StateProvider initialState=initialState reducer=reducer>
            <HoldingDetailsContainer />
        </StateProvider>
    );

然后我们将分派,我们的请求进入上下文

HoldingDetailsContainer 组件

const [data,setData]=useState();

function fethcData()
   fetchApi().then(res=>
       const data=res.data;
       setData(data)  //setData is useState function
)


//Now i need a side effect , to store data, after storing in state 
useEffect(()=>
    dispatch(
      type: 'storeApi',
      storeApi: data
    )
)

【讨论】:

它正在工作,我能够在 conext 中存储 API 驱动的数据。再感谢一件事,我们可以从子组件更新提供者数据吗? 欢迎您,是的,您可以用我给您的示例发送它。

以上是关于调用 REST API 并将其响应存储在 Context API 中的主要内容,如果未能解决你的问题,请参考以下文章

如何在rest api调用中构造json并使其同步

提高调用其他 API 的 Rest Webservice 性能的方法

Laravel REST API 和高 CPU 负载

错误响应上的 REST-API 不同的内容类型

如何传递 HttpInputStream 的内容并将其发送到 c# .net 中的另一个 Rest Api

自动化Rest API测试并将其与持续集成(CI-Jenkins)集成