I am facing a problem of fetching data (React, useEffect) - reactjs

I am trying to fetch data from the URL given below, sometimes I am getting but most of the time not in the console. I don't know about the problem I have tried with async-await but the result was the same.
https://quiet-forest-82433.herokuapp.com/myorders/?email=liza#liza.com
My code is:
const {user} = useAuth();
const [totalCart, setTotalCart] = useState({})
useEffect(() => {
const url = `https://quiet-forest-82433.herokuapp.com/myorders/?email=${user?.email}`
fetch(url)
.then(res => res.json())
.then(data => console.log(data))
}, []);

useEffect should have a dependency on user.
And don't call fetch until you have a valid user email. Currently, you're code will ask for email=undefined until the user populates, but the useEffect() will not fire again because there is no dependency on user.
useEffect(() => {
if (!user || !user.email) return
const url = `https://quiet-forest-82433.herokuapp.com/myorders/?email=${user?.email}`
fetch(url)
.then(res => res.json())
.then(data => console.log(data))
}, [user]);

Related

users array hook is not updating with all the list items

So I'm creating a simple MERN App, backend is working properly, but when working with useState hook in frontend is causing issues.
what im trying to do is to fetch "users" data(an array of object with field username) from backend endpoints, and updating the users array which is a hook, but it only updates with the last itm of the incoming username and not list of all usernames!!
code for fetching and updating the hook:
const [users, setUsers] = useState([]);
const getUsers = () => {
fetch("http://localhost:5000/users")
.then(res => res.json())
.then(data => {
console.log(data); //line 17
data.map((itm) => {
console.log([itm.username]) //line 19
setUsers([...users, itm.username])
})
})
.catch(err => console.log(err))
}
useEffect(() => {
getUsers();
}, [])
console.log(users); //line 30
what I want is to get a list of usernames in the "users" state!
something like this:
users = ["spidey", "thor", "ironman", "captain america"]
console.log is also not showing any errors...
console window
pls help, can't figure out where it's getting wrong?
The issue is two-fold, first you are using Array.prototype.map to iterate an array but are issuing unintentional side-effects (the state updates), and second, you are enqueueing state updates in a loop but using standard updates, each subsequent update overwrites the previous so only the last enqueued update is what you see in the next render.
Use either a .forEach to loop over the data and use a functional state update to correctly update from the previous state.
const getUsers = () => {
fetch("http://localhost:5000/users")
.then(res => res.json())
.then(data => {
console.log(data);
data.forEach((itm) => {
console.log([itm.username]);
setUsers(users => [...users, itm.username]);
})
})
.catch(err => console.log(err));
}
Or use the .map and just map data to the array you want to append to the users state.
const getUsers = () => {
fetch("http://localhost:5000/users")
.then(res => res.json())
.then(data => {
console.log(data);
setUsers(users => users.concat(data.map(itm => itm.username)));
})
.catch(err => console.log(err));
}
you can set the map result in a variable after that you can call the useState on it.
const [users, setUsers] = useState([]);
const getUsers = () => {
fetch("http://localhost:5000/users")
.then(res => res.json())
.then(data => {
console.log(data); //line 17
const userNameData = data.map(itm => itm.username)
setUsers(...users, userNameData)
})
.catch(err => console.log(err))
}
useEffect(() => {
getUsers();
}, [])
console.log(users);

How to fill users variable with data from GET request in React

I am making a GET call request to an API in order to fetch some data in my React component and save it to my users variable, but the data does not get saved, I get undefined when I console.log it. How can I set the response data from my GET call and save it in the users variable? Here is my attempt:
const [users, setPosts] = React.useState([]);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.json())
.then((data) => console.log(data));
setPosts(users.data);
}, []);
In the code you have posted, you aren't saving the data to users. Try this:
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.json())
.then(setPosts);
}, []);
This is how it should be do it:
const [users, setPosts] = React.useState([]);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.json())
.then((data) => setPosts(data););
}, []);
That way you set your users as data
Also as a hook rule you should define your state as follow const [users, setUsers] = useState()

how to handle delay with setting useState with API data

I am not the first one to have this problem.
but sadly, nothing of what i saw is working for me.
I wanna get data from API.
use the data to call another API.
and than return the data in or whatever.
so what happens is, the first fetch is going fine. im trying to set it inside a state.
but when the SECOND API runs, the STATE i need, is still empty... it hasnt been updated.
so the component cant render something that doesnt exist. so it crashes.
and also, something here causes multiple renders...
here is the code:
const SecondDisplay = () => {
const [firstData, setFirstData] = useState("")
const [secondData, setSecondData] = useState("")
const [errors, setErrors] = useState("")
const [loading, setLoading] = useState(true)
useEffect(() => {
navigator.geolocation.getCurrentPosition(function(position) {
// getLocation(32.0853, 34.7818)
fetch(`https://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=AZvK08ugMNLlAGAwDD9GQGj108Tm8OIP&q=${position.coords.latitude}%2C${position.coords.longitude}&language=en-us&details=false&toplevel=false`)
.then(res => {
if(!res.ok){
throw Error("Sorry, something went wrong. please try again later.")
}
return res.json()
})
.then(data => {
setFirstData({key: data.Key, name: data.AdministrativeArea.EnglishName})
})
.catch(error => {
setErrors(error.message)
setLoading(false)
})
})
}, [])
useEffect(() => {
if(firstData !== ""){
third(firstData.key)
}
}, [firstData])
let third = key => {
fetch(`http://dataservice.accuweather.com/currentconditions/v1/${key}?apikey=AZvK08ugMNLlAGAwDD9GQGj108Tm8OIP&language=en-us&details=true HTTP/1.1`)
.then(res => {
if(!res.ok){
throw Error("Sorry, something went wrong. please try again later.")
}
return res.json()
})
.then(data => {
setSecondData(data)
setLoading(false)
})
.catch(error => {
setErrors(error.message)
setLoading(false)
})
}
return(<p>{secondData.blabla}</p>)
What you can do is use a single useEffect() hook, and simply continue the promise chain once you get the response from the first request.
Here's a simplified example:
fetch(url)
.then(res => {
if (!res.ok) throw Error(msg)
return res.json()
})
.then(data => {
setFirstData(data)
return fetch(secondUrl, paramsBasedOn(data))
})
.then(res => {
if (!res.ok) throw Error(msg)
return res.json()
})
.then(data => {
setSecondData(data)
})
.catch(err => setError(err.message))

Changing url based on id and getting values from local storage. ReactJS

I am currently trying to access the logged in user's role by getting a value stored in localStorage, then based on that value I wanna set up my url and perform a fetch request. All of this is happening inside a ContextProvider.
My issue is that my fetch request is firing before I can obtain the value stored in localStorage.
Here is how I construct my url:
const [userRole, setUrerRole] = useState(0);
const [url, setUrl] = useState('');
let userID = localStorage.getItem('userID');
if (userID === 3){
setUrl("https://api.myjson.com/bins/00666")
}else if(userID === 1){
setUrl(process.env.REACT_APP_API_URL+"/api/v111/someexampleendpoint")
}
and I use the hook,
useMemo(() => {
fetch(url)
.then(response => response.json())
.then(response => {
setUserDetails(response);
})
.catch(error => console.log(error));
}, []);
Now the way I tried to do it originally is by creating a promise and chaining the functions but it didn't work.
function grabUserdStoredID(){
let userID = localStorage.getItem('userID');
if (userID === 3){
setUrl("https://api.myjson.com/bins/00666")
}else if(userID === 1){
setUrl(process.env.REACT_APP_API_URL+"/api/v111/someexampleendpoint")
}
return Promise.all
}
grabUserdStoredID.then(
useMemo(() => {
fetch(url)
.then(response => response.json())
.then(response => {
setUserDetails(response);
})
.catch(error => console.log(error));
}, []);
)
but it said that I cannot fire the hook in that way...
How can I call a fetch request inside a context after I've obtained
values from localStorage?
You have a lot of things going wrong here. I'm going to point out a few of them and give you an alternative structure at the end.
Your url can be derived from your state, so don't also store that in state.
Do not useMemo for an api call. useMemo is for caching computed values on render to prevent you from having to do it again unnecessarily. In this case you do want to put the results of your api call in state.
Fetch api calls with useEffect which then calls a state setter function after the fetch promise resolves. This way you can easily control the timing of the api calls with the dependency array.
localStorage.getItem() is not a problem here. It's synchronous api that returns a value immediately.
Putting this together, you end up with something like:
function SomeComponent() {
const [userDetails, setUserDetails] = useState()
let userID = localStorage.getItem("userID")
useEffect(() => {
let url
if (userID === "3") {
url = "https://api.myjson.com/bins/00666"
} else if (userID === "1") {
url = process.env.REACT_APP_API_URL + "/api/v111/someexampleendpoint"
}
fetch(url)
.then(response => response.json())
.then(response => {
setUserDetails(response)
})
.catch(error => console.log(error))
}, [userID])
return <div>Content Here</div>
}

React hooks - useEffect method keeps fetching

In many of my components, I have to use token from store to get data and represent it (header menu, footer menu, products on page, slider images, etc.). What I am trying to do is to get this data only if I don't have it, but React keeps sending requests every time token changes (as token is dependency), even though I clearly put condition and I can see it if I console.log it. What am I doing wrong?
const [cities, setCities] = useState([]);
useEffect(() => {
if (!cities.length) {
fetch(`.....&token=${props.token}`)
.then(response => response.json())
.then(data => {
if (data.data.results) {
setCities(data.data.results.cities)
}
})
}
}, [props.token, cities.length]);
The cities will be empty on first render anyway, so you don't need to check for its length and specify it as a dependency:
const [cities, setCities] = useState([]);
useEffect(() => {
fetch(`.....&token=${props.token}`)
.then(response => response.json())
.then(data => {
if (data.data.results) {
setCities(data.data.results.cities)
}
})
}, [props.token]);
You can also memoize the token to prevent it from triggering the useEffect callback:
const token = useMemo(() => props.token, []);
// EDITED BECAUSE OF THE COMMENTS
// should be outside of the function
let timesExecuted = 0
function fetch () {
useEffect(() => {
if(props.token){
timesExecuted = timesExecuted + 1
}
if (timesExecuted === 1) {
fetch(`.....&token=${props.token}`)
.then(response => response.json())
.then(data => {
if (data.data.results) {
setCities(data.data.results.cities)
}
})
}
}, [props.token]);
}
SO IT WILL COME every time BUT BE EXECUTED ONLY WHEN prop.token IS OKEY (feel free to modify the first IF based on token validations).

Resources