Set object in useEffect is not working in React - reactjs

I am new in React.I just want to show records in the table and I fetch data like
const [allowances, setAllowances] = useState([]);
useEffect(() => {
fetch("http://127.0.0.1:8000/allowances/")
.then(data => {
return data.json();
})
.then(data => {
setAllowances(data);
})
.catch(err => {
console.log("error",err);
});
}, []);
Here how I check length=>
<div>{allowances.length}</div>
if i log the data in before setAllowances(data) ,data has 3 records.But when I check allowances.length, there are no records. its show like <div></div>. So I think this setAllowances is not working.right? what is wrong?
Update
This is my data of i logged before setAllowance=>

You are not setting the data correctly. As per the contents of data, it should be:
setAllowances(data.allowance);

For useEffect hooks to update every single time that your state changes, you need to pass it as a parameter. This happens by passing allowances within the square brackets after you set your callback to useEffect. Check out this link

Related

useEffect is continually re-rendering when setting state

In my useEffect function, I'm first attempting to verify my 'auth' token using an axios call. After that, I then look to set state based upon the response I get from data either provided by the BE or stored in localStorage. Finally, I'm then attempting to console.log the state so that I can make sure the state is updated (which it is).
However, it's just continually re-rendering at the moment and not just loading once.
Note - I'm not displaying any of this information on the page itself, this is simply a processing screen used to complete some BE calls.
Here's my useEffect function:
useEffect(() => {
axios.post("/api/verifyToken", {
token: JSON.parse(localStorage.getItem('auth'))
})
.then((response) => {
setUserId(response.data)
setName(localStorage.getItem('name'))
}).then(() => {
console.log("Testing here..")
console.log(userId)
console.log(name)
})
}, [userId, name])
you need to remove userId and name from the dependency of effect (the [userId, name] parameter)
if you need to print out the result to console you may
print out the result from response of the promise instead of state
create another effect to print the userId and name
useEffect(() => { /** your HTTP request and set result to state */ },[])
useEffect(() => console.log(userId, name), [userId, name])

using multiple useEffect in order. fetching API after fetching the location

this is my first time using react. im working on a basic weather app.
i have a problem with using multiple useEffect hook in order. i need to fetch both the geolocation and then the weather APP api in order when the page load.
but i the location keep returning null, here's the code
useEffect(()=>{
navigator.geolocation.getCurrentPosition((position) => {
setLatitude(position.coords.latitude)
setLongitude(position.coords.longitude)
});
},[])
useEffect(()=> {
axios.get(`${api.base}weather?lat=${latitude}&lon=${longitude}&units=metric&appid=${api.key}`).then
((response) => {
console.log(response.data)
})
},[])
any solution will be appreciated. thank you
For this you could make the second useEffect dependent on your latitude and longitude states:
useEffect(()=>{
axios.get(`${api.base}weather?lat=${latitude}&lon=${longitude}&units=metric&appid=${api.key}`).then
((response) => {
console.log(response.data)
})
},[latitute, longitude])
This will call the useEffect every Time the latitude or longitude states have changed.
Your useEffects are both running asynchronously after the first render. If you need them to be ordered, then you should run them together in the same useEffect and add your code to fetch the response within the success callback of getCurrentPosition.
See this example:
useEffect(() => {
const fetchData = async() => {
navigator.geolocation.getCurrentPosition((position) => {
setLatitude(position.coords.latitude)
setLongitude(position.coords.longitude);
const response = await axios.get(`${api.base}weatherlat=${position.coords.latitude}&lon=${position.coords.longitude}&units=metric&appid=${api.key}`);
});
});
}, []);
Note: setState is also asynchronous, hence why we use the return position directly for the axios fetch request.
An alternative to this is, as the other answer mentioned, having your second useEffect use [latitude, longitude] in the deps array but if you don't want to constantly fetch weather API data every single time the lat/long changes, then you can just do it this way to run this once on initial component mount.

problem with usestate in firebase to save data

I have a problem that I can not solve try a thousand ways and nothing
I happen to show
I generate a state:
const [totalComidas, setTotalComidas] = useState({})
After that I do a useEffect to bring me the data from firebase and I want to save it in the state but it saves it empty
useEffect(() => {
const resultadoComidas = []
db.collection('menu semanal')
.get()
.then((snap) => {
snap.forEach((doc) => {
const comida = doc.data()
// comida.id = doc.id
resultadoComidas.push(comida)
console.log(resultadoComidas[0])
})
setTotalComidas(resultadoComidas)
console.log(totalComidas)
})
}, [])
And these are my results in console
enter image description here
The first result in the console is before adding it to the state and the second is the new state, which seems strange to me because it brings the data correctly but when I assign it to the state it assigns it to me empty.
It's normal for the totalComidas to be empty when you log it inside useEffect because the result of your setTotalComidas won't be showed in that particular useEffect. If you want to see the change of your totalComidas you need to have another useEffect like so
useEffect(() => {
console.log(totalComidas)
})
If you wonder why this is the case then read this. It explains the behavior of useEffect

state in useEffect second arguement Infinite loop

i have this small piece of code where i think i guess I'm doing it wrong
const [orders, setOrders] = useState([])
useEffect(() => {
fetch('/getOrders',{
headers:{
"Content-Type":"application/json",
"Authorization": "Bearer "+localStorage.getItem("jwt")
}
}).then(res=>res.json())
.then(orderList=>{
setOrders(orderList)
//console.log("myAdmin",orderList)
}).catch(err=>{
console.log("Error in Catch",err)
})
}, [orders])
Here the data is updated overtime by itself and i want my state updated every time the fetch data is different to the existing state , but regardless if the data is different or not, the state keep updating making the component re-render infinitely. Is there a solution for this?
Issue
Anytime an effect unconditionally updates a value that is in its dependency array it will cause render looping.
useEffect(() => {
fetch('/getOrders', { ... })
.then(res=>res.json())
.then(orderList=>{
setOrders(orderList); // <-- updates state, triggers rerender
})
.catch(err=>{
...
});
}, [orders]); // <-- updated state triggers effect callback
Possible Solution
It appears you are wanting to fetch every time the component renders and upon successful response (200 OK) check if the orders array is actually different. If it is then update state, otherwise ignore the update.
Remove the dependency array so the useEffect hook callback is called each time the component renders.
Check if the fetch request response is ok before accessing the response JSON data.
Check the order response data against state. If the arrays are different lengths, update state, otherwise you will need to check element by element to determine if the array is different or not. *
Updated effect hook
const [orders, setOrders] = useState([])
useEffect(() => {
fetch("/getOrders", {
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + localStorage.getItem("jwt")
}
})
.then((res) => {
if (!res.ok) {
throw new Error("Fetch is not OK");
}
return res.json();
})
.then((orderList) => {
if (orders.length !== orderList.length) {
setOrders(orderList);
} else {
for (let i = 0; i < orders.length; i++) {
// *** Your actual equality condition may be different, i.e. if they are objects ***
if (orders[i] !== orderList[i]) {
setOrders(orderList);
return;
}
}
}
})
.catch((err) => {
console.error("Error in Catch", err);
});
});
* This is an O(n) check every time so an optimization that can be made may be to also return and store an "update" hash. If the hash is the same as the previous request, skip state update. This could be something as simple as generating a new GUID for the update in backend and returning it with data.
Basicaly [orders] in your code means: call what inside useEffect each time orders change, and each time useEffect is called , it update again the orders ... and you get your infinite loop
useEffect(() => {
}, [orders])
you should change [orders] into [].
res=>res.json() will create a new refrance to your object, and changing your referance to your object means it changed, for example [1,2,3] if you pass again [1,2,3] it will not be the same objct even thow it looks the same. v=[1,2,3], you pass v, and then v[0]=-1, passe v again it will be considred the same since it has the same referance.
Best way to fix this is to compare them manualy depending on your case, and when they aren't the same, you use somthing like [...orders] which will create new refrence and it will invoke useEffect again.
try to set state with prevState argument, so you will not have to include any dependency.
setOrders((prevState) => ({
...prevState, orderList
}))

After Pushing a Array Element in react.js using useState and useEffect it's looping infinite after update the state. How to solve?

I have push some a image elements in object array it's working fine but how to update the state?
const url = "https://jsonplaceholder.typicode.com/posts";
const [posts, setPosts] = useState([]);
const postsMap = posts.map(post => {
return {...post, "image": `image-${post.id}.jpg`}
})
console.log("Added Post Image", postsMap);
useEffect(()=>{
fetch(url)
.then(res => res.json())
.then(data => {
setPosts(data)
console.log(data);
})
}, [postsMap]);
I would say its because -
setPosts(data) in useEffect() updates post
update in post updates postsMap
update in postsMap triggers a re-render of the component
repeat the cycle.
I think the infinite loop is probably because of the wrong parameter passed to the dependency array provided to useEffect as the second parameter. I think passing an empty array as a parameter to useEffect's second argument should solve the problem.
Because your useEffect is dependend on a variable that changes within it self (setPosts). So you create an infinite Loop. You don’t need postmap as dependency, use url as dependency.

Resources