Set data on createContext with asynchronous API call - javascript

I'm a very beginner in React and Next.JS. I'm doing an app and I'm using the useContext hook. So, I have this code
import { createContext } from 'react';
let data;
fetch(API_URL)
.then(response => response.json())
.then(result => {
data = result.data;
})
.catch(error);
export const UserContext = createContext(data);
The problem is that when the context is created, the value of 'data' is null. Is there a way to do this asynchronously?

Something like this should do it:
import { useState, useEffect, createContext } from 'react';
const UserContext = ({children}) => {
const [data, setData] = useState();
const Ctx = createContext();
useEffect(() => {
fetch(API_URL)
.then(response => response.json())
.then(result => {
setData(result.data);
})
.catch(error);
}, []};
return (
<Ctx.Provider value = {data} >
{children}
</Ctx>
);
}
Didn't test it, but this should give you an idea; You can use it like
<UserContext>
// your code here
</UserContext>
A better way to do it would be to extract the fetch logic in a custom hook:
const data = useUserData(); // fetch logic here
<UserContext value={data}>
// your code here
</UserContext>
but since you are a beginner in React, I would keep it simple

Related

How can I access data in another component?

I'm sorry if my question is too ridiculous, because I'm new to programming.
I created a project with React, I have 3 different components: navbar, sidebar and data.
I received json data from an api using hooks in my data component.
import { useEffect, useState } from "react";
export const Data = () => {
const [data, setData] = useState();
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((json) => setData(json));
}, []);
};
Now, how can I access the "data" state in the data component from other components?
I don't want to use Context api, because I've heard that it is only used in cases where the state affects all components, like authentication
thanks in advance for your help
I have added few lines in your codesandbox. I think this is same that you want to achieve
codesandbox
Thank you to everyone who helped me. Actually, I realized that the title is not correct. What I wanted to do was to use the data brought outside the component inside the component. I did this by creating custom hooks. If anyone is curious, I leave the code below.
import { useEffect, useState } from "react";
export default function useData(id = 1) {
const [data, setData] = useState([]);
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
.then((response) => response.json())
.then((json) => setData(json));
}, []);
return { data };
}
Then I import and use the useData hook I created in any component.
(I'm not even sure it's called a hook.)
Example: const {data} = useData(4)
You could maybe use the module.exports function in the data component and then just call it in the necessary components. For example:
import { useEffect, useState } from "react";
export const Data = () => {
const [data, setData] = useState();
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((json) => setData(json));
}, []);
};
module.exports = data;
Then in the navbar component for example you call it and use it where it is necessary:
const Navbar = () => {
const data = require(../Data)
...
...
...
}
Hope it helps.

Trying to fetch APi but it is not displaying the data

I have created Context API I am trying to fetch the data from my API so I can use the state globally, but is not doing it. I am not getting any errors in the console. But when I try to fetch from the Other Component, I am getting data in the console. Just in the Context, I am not getting it.
import React, {useState, useEffect}from 'react'
import ITrucks from '../interface/truck';
import axios from 'axios';
export const TrucksContext= React.createContext({})
export const TrucksProvider:React.FC = ({ children } ) => {
const [isLoading, setIsLoading] = useState(false);
const [trucks, setTrucks] =useState<ITrucks[]>([])
const [isError, setIsError] = useState(false);
const fetchData = () => {
axios
.get('https://localhost:7000/trucks')
.then((response) => {
setIsLoading(false);
setTrucks(response.data);
console.log(response.data)
})
.catch((error) => {
setIsLoading(false);
setIsError(true);
console.log(error);
});
};
useEffect(() => {
fetchData();
}, []);
return (
<TrucksContext.Provider
value={{trucks}}
>
<>
{children}
</>
</TrucksContext.Provider>
);
}
try setTrucks([...response.data])
The problem could be in the API itself. When an API has an error it often return empty data to Axios instead of an error, it depends on the return statement

undefined useState React after setting it to an object

Goal: Fetch data from api then assign it to a state for further processing.
Issue: After setting the data to my useState it is still undefined.
Questions:
How would one solve this problem?
Am I misunderstanding the useState hook?
import "./styles.css";
import axios from "axios";
import { useEffect, useState } from "react";
export default function App() {
const [userData, setUserData] = useState();
const functionz = () => {
return axios
.get("https://randomuser.me/api/")
.then(({ data }) => data.results);
};
useEffect(async () => {
const data = await functionz();
setUserData(data);
}, []);
if (userData) {
console.log(userData);
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Edit to see some magic happen!</h2>
</div>
);
}
You have to make sure your function is returning the axios call. Then await whatever comes out of it in your useEffect. Then proceed to adding it to your state. See example.
import React, { useState, useEffect } from 'react'
import axios from "axios";
const Api = () => {
const [usersData, setUsersData] = useState(null)
const fetchRandomUserData = () => axios.get('the-url')
useEffect(() => {
fetchRandomUserData()
.then(resp => {
setUsersData(resp.data.results)
})
.catch(e => {
console.log('Error: ', e)
})
}, [])
console.log(usersData)
return <div></div>
}
export default Api

React Context API, Data loading twice. Once with the data and the other without

Here is how I have created a Context for simple program I am writing
import React, { useState, createContext, useEffect } from "react";
export const PhotoContext = createContext();
export const PhotoProvider = (props) => {
const [photo, setPhoto] = useState([]);
useEffect(() => {
console.log("Use Effect Runs HAHAHAH");
console.log("HAHAHAHAHAHAHAH");
fetchPhotos();
async function fetchPhotos() {
const url =
"https://raw.githubusercontent.com/bobziroll/scrimba-react-bootcamp-images/master/images.json";
fetch(url)
.then((res) => res.json())
.then((arr) => {
setPhoto(arr);
})
.catch(console.log("ERROR"));
}
}, []);
return (
<PhotoContext.Provider value={[photo, setPhoto]}>
{props.children}
</PhotoContext.Provider>
);
};
There is another file where I want to load the data in the photos variable. Here is the code for it. I have used setTimeout to see where exactly is the problem. It seems whenever the statement in setTimeout runs, the value in console in returned twice. First, it is empty and the second has the actual value. But since, I try to access the photos.url, and since the first time it is undefined, the program collapses.
import React, { useState, useContext } from "react";
import { PhotoContext } from "../Context/PhotoContext";
const Photos = (props) => {
const [photos, values] = useContext(PhotoContext);
setTimeout(() => {
console.log(photos[0].url);
}, 3000);
return <div>{}</div>;
};
export default Photos;
Help would be really appreciated.
Didn't see the problem. I created sandbox for your example.
https://codesandbox.io/s/inspiring-lovelace-5r1gb?file=/src/App.js

Cannot read states in Redux with React Hooks, Cannot read property '_id' of null

I have a MERN Web-app, which I am learning React Hooks.
What I am trying to do : Access the states in my Redux.
When i refresh the page,
The error : TypeError: Cannot read property '_id' of null
I am not able to access it when I clearly see the states in my redux developer tools.
I have tried console.log(auth.isAuthenicated) but it returns null. However, when I do console.log(auth), it returns [object,object]. Which confuses me because I can't get inside.
Currently, I am researching and will look into react-persist. I was wondering if anyone can help me with my issue without react persist or explain why it might be a good idea to use it.
My redux :
token(pin):"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlNDFmYTNhOWIwZjk0NmU5N2Q5MmY4MiIsImlhdCI6MTU4Mzk0NzA5MSwiZXhwIjoxNTgzOTUwNjkxfQ.pysX20n4cxKK5NqcXPosIejSvCN3pbcSNpQvEOX9kBE"
isAuthenticated(pin):true
isLoading(pin):false
_id(pin):"5e41fa3a9b0f946e97d92f82"
name(pin):"admin"
email(pin):"admin#gmail.com"
date(pin):"2020-02-11T00:50:02.183Z"
__v(pin):0
snippets of my code :
import React, { useState, useEffect } from "react";
import { TiDelete } from "react-icons/ti";
import Restaurants from "../Restaurant/Restaurants";
import NutritionalGraphs from "../D3Graphs/NutritionalGraphs";
import { connect, useDispatch, useSelector } from "react-redux";
import axios from "axios";
import { addItem, deleteItem } from "../../../actions/itemActions";
import IngredientsPredictions from "../Predictions/IngredientsPredictions";
import { loadUser } from "../../../actions/authActions";
import { createSelector } from "reselect";
const UserProfile = props => {
const dispatch = useDispatch();
const [newUserFavorite, setNewUserFavorite] = useState("");
const [favArray, setFavArray] = useState([]);
const tokenRecognized = useSelector(state => state.auth.token);
// const userID = useSelector(state => state.auth.user._id);
const auth = useSelector(state => state.auth);
const userStates = createSelector();
// name
// name => props.auth.user.name,
// userID => props.auth.user._id
// foodFavoritesArray => foodFavoritesArray.state.item.items
useEffect(() => {
dispatch(loadUser(tokenRecognized));
// console.log(userStates.userID);
console.log(auth.isAuthenicated);
axios
// .get(`/api/items/item/${userStates.userID}`)
.get(`/api/items/item/${auth.user._id}`)
.then(res => {
return res.data;
})
.then(json => {
setFavArray(json);
})
.catch(err => console.log(err));
}, [userStates.userID]);
console.log(favArray);
it is breaking at : .get(`/api/items/item/${auth.user._id}`):
Big thank you for the read.
You need to wait for your loadUser action to complete before you can access the data. I assume that it makes an async request. You need to that in two steps:
useEffect(() => {
// fetch user data when component mounts
dispatch(loadUser(tokenRecognized));
}, []);
useEffect(() => {
// check if user has been fetched (will not be the case on mount)
if (auth.user) {
axios
.get(`/api/items/item/${auth.user._id}`)
.then(res => {
return res.data;
})
.then(json => {
setFavArray(json);
})
.catch(err => console.log(err));
}
}, [auth.user]); // perform this when `auth.user` changes

Categories

Resources