Read the setState value immediately after setting in useEffect React - reactjs

I want to fetch info from the API in useEffect, set it using setState and immediately use it for further filtering.
the code looks like this:
const[usersInfo, setUsersInfo] = setState('')
useEffect(()=>{
async function fetchUsers(){
const response = await fetch(`http://localhost:8083/api/patient/findAll`);
const json = await response.json();
setUsersInfo(json)
}
fetchUsers()
console.log('users info', usersInfo)
},[])
I tried to pass the dependency for usersInfo but then it is running in loop.
What can I do it to prevent this behavior?

You need to add a second useEffect that detects changes to usersInfo.
const [usersInfo, setUsersInfo] = setState("");
useEffect(() => {
async function fetchUsers() {
const response = await fetch(`http://localhost:8083/api/patient/findAll`);
const json = await response.json();
setUsersInfo(json);
}
fetchUsers();
// console.log("users info", usersInfo); // commenting out this code since it will always print empty string
}, []);
useEffect(() => {
if(usersInfo !== ""){
// Do stuff here with usersInfo
}
}, [usersInfo]);

Related

useEffect is causing infinite loop when use state as dependency

Here simply I am fetching data from mysql DB and storing it in state and in order to fetch this data:
const [orders, setOrders] = useState([]);
To fetch data I am using different functions and finally I am calling those functions using useEffect simple enough and so for everything is working perfectly but the problem comes whenever I use the state as dependency where I am storing data beacause if I dont do that then I have to manually refresh the page for latest changes and I have tried every given solution on stackoverflow but any of the solution didnt work so someone can please help me how can I use this state as dependencey without causing infinite loop:
const [orders, setOrders] = useState([]);
const loadData = async () => {
const response = await fetch("http://localhost/k-shop/load.php");
const result = await response.json();
setOrders(result);
};
const loadTotal = async () => {
const response = await fetch("http://localhost/k-shop/amount.php");
const result = await response.json();
setTotal(result);
};
useEffect(() => {
loadData();
loadTotal();
}, [orders]);
console.log(orders);
If you move the state into the useEffect dependency, you can then check if it is empty, and only set it when that check passes.
It will set the state once to populate and not pass the check again.
const [orders, setOrders] = useState([]);
const loadData = async () => {
const response = await fetch("http://localhost/k-shop/load.php");
const result = await response.json();
setOrders(result);
};
const loadTotal = async () => {
const response = await fetch("http://localhost/k-shop/amount.php");
const result = await response.json();
setTotal(result);
};
useEffect(() => {
if(orders.length === 0) {
loadData();
}
// you can do the same with checking loadTotal() state
}, [orders]);
console.log(orders);
Avoid ,non-primitive data types in dependencyArray ,
useEffect(() => {
loadTotal();
loadData();
}, [total, orders.length]);
every times you "setOrders" means you change the state,every times you change the state,means the "useEffect" will do again.that cause infinite loops.why not try useEffect(() => {loadData()}, [])?

Why is my React useEffect not loading again when I refresh the page?

I am using a useEffect to get information from firebase and set my redux state thereafter. When I open the page for the first time, all my components contain the correct information. As soon as I refresh the page, all the information is set to nothing? I think it is because the useEffect does not execute again for some reason. Here is my code below:
useEffect(async () => {
setLoading(true);
const fetchData = async () => {
await getConfigs().then((response) => {
const obj = response;
setRedux(obj[0]);
});
};
fetchData();
}, []);
I think the problem is that you provide an async function as a callback to useEffect, which is not allowed. Just get rid of it, like so:
useEffect(() => {
setLoading(true);
const fetchData = async () => {
// Also, you either await or use .then(), not both
const response = await getConfigs();
const obj = response;
setRedux(obj[0]);
};
fetchData();
}, []);

setState never gets set in useEffect after API call responds with data

I'm trying to update state immediately after data comes in from the API. The data is coming in, I can see it using the console.log right below my API request. All of the data is right but for some reason, setState never sets in my hook. It just returns and empty array even after the console displays data.
const [experienceData, setExperienceData] = useState([]);
const { match = {} } = props;
useEffect(() => {
async function fetchData() {
if (Object.keys(match.params).length > 0) {
const response = await ApiService.getExperiences(match.params.experieneId);
console.log(response)
setExperienceData(response)
}
}
fetchData();
}, []);
I must be doing something wrong but I can't figure out what that is. Hoping someone on here has run into the same issue.
UPDATE: I just changed everything over the a class and duplicated the exact code on another file and ran into the exact same issue. The console updates with the data, but the setState on the line immediately after the data does not setState.
async componentDidMount() {
if (Object.keys(this.props.match.params).length > 0) {
const response = await ApiService.getExperiences(this.props.match.params.experieneId);
console.log(response[0])
this.setState({ experienceData: response[0], occurrenceData: response[0].occurrences });
}
}
You have to useSetState in a proper way, the issue is in the setExperienceData
const [experienceData, setExperienceData] = useState({response:""});
const { match = {} } = props;
useEffect(() => {
async function fetchData() {
if (Object.keys(props.match.params).length > 0) {
const response = await ApiService.getExperiences(match.params.experieneId);
console.log(response)
setExperienceData(experienceData => ({ ...experienceData, response: response }));
}
}
fetchData();
}, []);
return(<div>check {experienceData.response}</div>)
I see you left the dependency array empty. This tells React to run this effect only once: when the component first renders. If you want your useEffect to respect your state hook, put setExperienceData inside the dependency array
const [experienceData, setExperienceData] = useState([]);
const { match = {} } = props;
useEffect(() => {
fetchData();
}, [props.match.params]);
const async fetchData = () => {
if (Object.keys(match.params).length > 0) {
const response = await ApiService.getExperiences(match.params.experieneId);
console.log(response)
setExperienceData([...response])
}
}
Could you please try passing [match.params] as the second argument to your useEffect.

How to setstate after fetch data React hook [duplicate]

This question already has answers here:
The useState set method is not reflecting a change immediately
(15 answers)
Closed 10 months ago.
Code :
Result : Not have data in state
help me pls , thanks!
setState is asynchronous that's why you are seeing books as empty array. Here is a quote from the React docs:
The setState function is used to update the state. It accepts a new
state value and enqueues a re-render of the component.
One thing you may be doing wrong is in your useEffect callback. If your effect returns a function, React will run it when it is time to clean up. And you don't want the setState functions in fetchData to be invoked during clean up as the component will probably be unmounted.
If you just want the fetchData to only run once after the component mounts, here is a possible solution:
useEffect(() => {
// put the fetchData inside the effect
async function fetchData() {
setLoading(true);
const name = await getNameGroup();
const tmp = await getAll(name);
console.log(tmp);
setBooks(tmp);
console.log(books); // may not be the same as tmp, but you will see the updated state in the next render
setLoading(false);
}
fetchData();
},[]}
You should read more about useEffect hook in the React docs.
It's a stale closure problem.
Your useEffect where the fetchData is being called, has an empty dependency array. Within the fetchData function, which is inside useEffect, you are trying to print books which one first load, was initialized with an empty array.
All hooks hold the same reference to the variables with which they were initialized, till the dependencies change. To get an updated state, they depend on the dependency array. Since your dependency array doesn't specify books, it won't refresh the reference of books in your fetchData function either. Read more about the stale closure problem here
That's why your books variable is showing stale data.
export default function() {
// fetch data here
// runs only once because of empty dependency array
useEffect(() => {
let isCancelled = false
// define the fetchData inside the `useEffect` so that
// you can detect if the component has been unmounted
// using `isCancelled`
const fetchData = async () => {
const tmp = await getAll()
// only update state if component isn't unmounted
// if you try to update state on an unmounted component,
// React will throw an error
if (!isCancelled) {
setIsLoading(false)
setBooks(tmp)
}
}
if (!isCancelled) {
setIsLoading(true)
fetchData()
}
// cleanup
return () => {
isCancelled = true
}
}, [])
}
const [dataArray, setDataArray] = useState([]);
async function fetchData() {
try {
setIsLoading(true);
const response = await getNameGroup();
setDataArray(response);
} catch(error) {
// handle error
} finally {
setIsLoading(false);
}
}
This is an example code that is working and you can apply:
const [data, setData] = useState([]);
const [hasError, setErrors] = useState(false);
async function fetchData() {
const LibraryQuery = JSON.stringify({query: `query { species { id name description } }`});
const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
const res = await fetch('http://localhost:3000/graphql',{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': token
},
body: LibraryQuery
});
res
.json()
.then(res => setData(res.data))
.catch(err => setErrors(err));
}
useEffect(() => {
fetchData();
}, []);

async fetch triggered three times

I use this in my react app to fetch data from my backend server:
React.useEffect(() => {
const fetchWidgets = async () => {
const response = await fetch("http://localhost:1202/data");
const responseData = await response.json();
setData(responseData);
console.log(responseData);
};
fetchWidgets();
});
It fetching data works fine, but the function seems to be triggered three times for some reason.
responseData is logged three times.
React.useEffect runs every time after component renders, unless you tell it not by defining a dependency array as its second argument; since you are setting a state inside its body which causes the comonent to re-render, you will see it happens multiple times. to fix the problem you may pass an empty array [] it will only run once after first render and acts like componentDidMount in class components. or add some dependency to run only if the dependencies change;
React.useEffect(() => {
const fetchWidgets = async () => {
const response = await fetch("http://localhost:1202/data");
const responseData = await response.json();
setData(responseData);
console.log(responseData);
};
fetchWidgets();
},[]);
Use Empty Brackets for the second parameter of useEffect.
React.useEffect(() => {
const fetchWidgets = async () => {
const response = await fetch("http://localhost:1202/data");
const responseData = await response.json();
setData(responseData);
console.log(responseData);
};
fetchWidgets();
},[]);
That will ensure the useEffect only runs once.

Resources