I want to send the array of objects in ContextProvider value attribute, so that i can use it in another component using useContext() hook. So that in the component i can destructure values from the array and map the array and display it on the browser.
Here is the ContextProvider file code:-
import React, { useState, useEffect, createContext } from "react";
import axios from "axios";
const APIContext = createContext();
export const APIContextProvider = (props) => {
const [orders, setOrders] = useState([]);
useEffect(() => {
const fetchData = async () => {
const res = await axios.get("/api/orders");
setOrders(res.data);
//res.data returns ARRAY OF OBJECTS
console.log(res.data);
};
fetchData();
}, []);
return (
<APIContext.Provider value={?}>{props.children}</APIContext.Provider>
);
};
Why you dont pass objects as value={{objects}} and then later access it as const {objects} = useContext(APIContext)
Related
I'm using useContext in a component page, and it correctly gets datas through useContext in a type of a property.
colorContex.js
import { createContext, useEffect, useState, useContext } from 'react';
// create context object
export const ColorContext = createContext({});
export const ProductsProvider = (props) => {
const [data, setData] = useState(null);
useEffect(() => {
async function fetchAPI() {
const res = await fetch(url);
const posts = await res.json();
setData(posts);
}
fetchAPI();
}, []);
return <ColorContext.Provider value={data}>{props.children}</ColorContext.Provider>;
};
headerDefault.tsx
const colors = useContext(ColorContext);
console.log(colors);
// the data shows up correctly in console log
const colorData = colors.response;
// the error message( the property doesn't exist type {}. )
Google development
the data is correct and a type of property.
How can I get property datas?
The problem here is this line:
export const ColorContext = createContext({});
TypeScript infers the context type from this line and {} does not have a .response property.
To fix this, define the type of your Context:
type ColorContextType = null | {
response: {
result_info: any, // TODO: type this correctly
result_list: any[], // TODO: type this correctly
}
}
export const ColorContext = createContext<ColorContextType>(null);
export const ProductsProvider = (props) => {
const [data, setData] = useState<ColorContextType>(null);
I have an existing context for products. Where initially I used some mock data as shown below STORE_DATA to render the components. Now I need to replace that mock data and connect to a Node.js api which is available on my local port (created the api I after I created the react-app).
import React, { createContext, useState } from 'react';
import STORE_DATA from '../shop';
export const ProductsContext = createContext();
const ProductsContextProvider = ({ children }) => {
const [products] = useState(STORE_DATA);
return (
<ProductsContext.Provider value={{ products }}>
{
children
}
</ProductsContext.Provider>
);
}
export default ProductsContextProvider;
Just created a helper.js file witht he following to fetch the data:
import {useEffect} from "react";
const fetchData = () => {
return fetch("https://localhost:8081/products") <<tested on postman and works fine.
.then((response) => response.json())
.then((data) => console.log('Fetching Data:',data));
}
How to replace the mock data on the context file and use this fetchData() using useEffect within the context? What code should change?
Tried the following, but didn't work, can't even print the console.log:
import React, { createContext, useState, useEffect } from 'react';
import { fetchData } from '../helpers';
export const ProductsContext = createContext();
const ProductsContextProvider = ({ children }) => {
const [products, setProducts] = useState(null);
useEffect(() => {
setProducts(fetchData());
}, []);
return (
<ProductsContext.Provider value={{ products }}>
{
children
}
</ProductsContext.Provider>
);
}
export default ProductsContextProvider;
The issue was that it was returning the following error (explained):
net::ERR_SSL_PROTOCOL_ERROR (on chrome)
Solution: Use http:// instead of https:// in the URL's in the following code:
const fetchData = () => {
return fetch("http://localhost:8081/products")
.then((response) => response.json())
.then((data) => console.log('Fetching Data:',data));
}
I am following an article: https://dev.to/mongopark/learn-react-hooks-and-context-api-by-building-a-recipe-search-app-2-1g3o. In it, he uses useState and useEffect inside his created Context. When I try to do the same. I get errors sayin, " Line 10:28: React Hook "useState" is called in function "dataProvider" which is neither a React function component or a custom React Hook function react-hooks/rules-of-hooks" for all the hooks. I would like to just know what I am doing wrong here.
import React, {useState, useEffect, createContext} from 'react';
import { headerFooter } from '../../api/Api';
import {setHeaderFooter} from '../../functions/generalFunctions'
import {grabUserInventory} from '../../api/Api'
import {getAllOrgs} from '../../api/Api'
const dataContext = createContext()
const dataProvider = (props) => {
const [data, setData] =useState("")
const [combined, setCombined] =useState(0)
const [inventory, setInventory] =useState([])
const [notes, setNotes] =useState([])
const [orgs, setOrgs] =useState([])
const [renderedData, setRenderedData]=useState([])
const [progress,setProgress] = useState(true)
useEffect(()=>{
console.log(props.match.params.token)
headerFooter(props.match.params.token)
.then(res=>{
setData(res)
setHeaderFooter(res.header,res.footer)
return grabUserInventory(res.user_id)
.then(data=>{
setInventory(data)
setRenderedData(data)
setProgress(false)
return getAllOrgs()
.then(data=>{
var outputData = data.map( Object.values );
setOrgs(outputData)
})
})
})
.catch(err=>console.error(err))
}, []);
return (
<dataContext.Provider value={{
data,
setData,
combined,
setCombined,
inventory,
setInventory,
orgs,
setOrgs,
renderedData,
setRenderedData,
progress,
setProgress
}}>
{props.children}
</dataContext.Provider>
);
}
export { dataProvider, dataContext }
I am trying to use the context below to fetch the data from the api, then pass it down to other components. The data is from unsplash, so I would like to filter it out first using a keyword set by the user. However, the first array returned by the function is empty, but if I console.log() it, I get all the data as expected
import React, {useState, createContext} from 'react';
import axios from 'axios';
export const ImageContext = createContext();
export const ImageContextProvider = ({children}) => {
const [images, setImages] = useState([]);
const count = 15;
const start = 1;
const getImages = async (keyword) => {
await axios.get(`api/photos?count=${count}&start=${start}&keyword=${keyword}`)
.then(res => setImages(res.data.results));
}
return (
<ImageContext.Provider value={{images, getImages: getImages }}>
{children}
</ImageContext.Provider>
);
}
This is the component that passes the keyword to the context that will be used to fetch data from the API
import React, { useState, useContext} from 'react';
import { ImageContext } from '../../Context/ImageContext';
export const SearchBar = () => {
const { getImages, images } = useContext(ImageContext);
const[keyword, setKeyword] = useState('');
const searchImages = async (e) => {
e.preventDefault();
await getImages(keyword);
console.log(images);
}
return (
<form onSubmit={searchImages}>
<input type='text' placeholder='Search Images' value={keyword} onChange={(e) =>
setKeyword(e.target.value)}/>
<input type='submit'/>
</form>
);
}
You are almost there :)
Since you are using React hooks, you need useEffect so that you can be able to send Http request. It is equivalent to `componentDidMount.
How to use it?
import React, {useState, createContext, useEffect} from 'react';
useEffect(() => {
const result = axios.get(`api/photos?count=${count}&start=${start}&keyword=${keyword}`)
.then(res => setImages(res.data.results)); // remember to update your state
}, []); // don't forget to pass an empty array
Take a look at your getImages() function:
const getImages = async (keyword) => {
await axios.get(`api/photos?...`).then(...);
}
If I’m right that is a wrong construction as you’re mixing and await and a then(). Furthermore, your getImages() is not returning a value. I think the following solves your problem:
const getImages = async (keyword) => {
const res = await axios.get(`api/photos?...`);
setImages(res.data.results);
return res.data.results;
}
im trying to create an api request with the header value, that is received from a context component. However, as soon as the page component is loaded, it throws an Cannot read property '_id' of null exception. Is there a way to run the useEffect function, as soon as the context is loaded?
main component:
import React, { useState, useEffect, useContext } from "react";
import "./overview.scss";
/* COMPONENTS */;
import axios from 'axios';
import { GlobalContext } from '../../components/context/global';
const Overview = () => {
const [bookings, setBookings] = useState([]);
const [loaded, setLoaded] = useState(false);
const [user, setUser] = useContext(GlobalContext);
useEffect(() => {
axios
.get(`/api/v1/bookings/user/${user._id}`)
.then(res => setBookings(res.data))
.catch(err => console.log(err))
.finally(() => setLoaded(true));
}, [user]);
context component:
import React, {useState, useEffect, createContext} from 'react';
import jwt from 'jsonwebtoken';
/* GLOBAL VARIABLES (CLIENT) */
export const GlobalContext = createContext();
export const GlobalProvider = props => {
/* ENVIRONMENT API URL */
const [user, setUser] = useState([]);
useEffect(() => {
const getSession = async () => {
const user = await sessionStorage.getItem('authorization');
setUser(jwt.decode(user));
}
getSession();
}, [])
return (
<GlobalContext.Provider value={[user, setUser]}>
{props.children}
</GlobalContext.Provider>
);
};
The issue here is useEffect is running on mount, and you don't have a user yet. You just need to protect against this scenario
useEffect(() => {
if (!user) return;
// use user._id
},[user])
Naturally, when the Context fetches the user it should force a re-render of your component, and naturally useEffect should re-run as the dependency has changed.
put a condition before rendering you GlobalProvider, for example:
return (
{user.length&&<GlobalContext.Provider value={[user, setUser]}>
{props.children}
</GlobalContext.Provider>}
);
If user is not an array just use this
return (
{user&&<GlobalContext.Provider value={[user, setUser]}>
{props.children}
</GlobalContext.Provider>}
);