I have a requirement in my react application to store API driven data in Context API. Class functions are not there only functional ponents we are using.
I have tried to use await with fetch call but no success
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>
)
}
If i use await in front of useGetResourceApi
then it throws error "Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead."
Is it possible to store API driven data in context API
I have a requirement in my react application to store API driven data in Context API. Class functions are not there only functional ponents we are using.
I have tried to use await with fetch call but no success
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>
)
}
If i use await in front of useGetResourceApi
then it throws error "Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead."
Is it possible to store API driven data in context API
Share Improve this question asked Jul 29, 2019 at 4:23 Puneet BhandariPuneet Bhandari 3562 gold badges5 silver badges16 bronze badges 2-
Is
useGetResourceApi
a custom hook? – Shubham Khatri Commented Jul 29, 2019 at 4:34 - This is a custom function written that is doing axios call internally – Puneet Bhandari Commented Jul 29, 2019 at 5:58
2 Answers
Reset to default 12I can't see the details of your API call or of the HoldingDetailsContainer, and also I can't see your imports, but below is a full (contrived) example of using the Context API + Hooks + function ponents to fetch data via a REST API and provide it to ponents:
// App.jsx
import React from "react";
import { APIContextProvider } from "./apiContext";
import Users from "./Users";
export default function App() {
return (
// wrap your app (or just ponents that need to consume the context)
<APIContextProvider>
<div className="App">
<h1>Hello CodeSandbox</h1>
// the Users ponent 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 plex state you might set up useReducer for Redux-like state updates
const [users, setUsers] = useState([]);
// useEffect is a lifecycle method for function ponents, 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./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;
}
// Users.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 ponents
// ofc this simple example can be adapted to make further calls
{users.map(u => (
<li key={u.id}>{u.username}</li>
))}
</ul>
);
}
A working, live version of the above code can be found in this sandbox I put together: https://codesandbox.io/s/context-api-fetch-data-provider-example-0rymy
please look at this gist : https://gist.github./nimahkh/9c008aaf2fd2d1cc83cd98c61e54979a
i think you have to change your structure , storing in context , is like storing in Database or redis cache .
also , storing in context is an async process , so you have to fetch api , then store it in context .
i will show you a code with my gist example
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>
);
}
then we are going to dispatch , our request into context
HoldingDetailsContainer Component
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}
})
})