Asynchronous behavior of React state

I have problems in handling asynchronous behavior of the state in React.

For example:

I have 2 tables:
1. List of Villages
2. List of Farmers

I have 2 states handling these data:
1. const [villages, setVillages] = useState([])
2. const [farmers, setFarmers] = useState([])

I have 2 functions:
1. assignVillage(): this function gets called when I select a village from a dropdown and click a button called “Assign Village”, which in turn also calls the setVillages() and updates the villages table by adding the new village.

assignVillage() {
		// "village" is the selected village from the dropdown, which is maintained as a different state
		const newVillages = [...villages, village];
		setVillages(newVillages);
	}
  1. fetchFarmers(village): this function takes a village as the parameter and calls an api to fetch the farmers list from the particular village and calls the setFarmers() to updates the farmers table.
fetchFarmers(village) {
		axios.get(url).then(res => {
			const farmers = [...res.farmers];
			setfarmers(farmers)
		})
	}

fetchFarmers() is called whenever I select a village by clicking the village name from the table or simply calling the function from anywhere in the component.

Issue:
There is a case when I had to do it simultaneously, like I am adding village in the list and selecting the added village to get the farmers list, which actually is the issue.

assignVillage()
	fetchFarmers(village)

As the state change is asynchronous, the village list in the fetchFarmers() is stale one making it an issue. As the new villages is still being updated by setVillages(), the village list in the fetchFarmers() is not the updated one. If in any way, I could call fetchFarmers() after the state updation would be better. Any solution without using useEffect() will be really helpful.

Please suggest me a solution for this.

1 Like

without using useEffect? Even though that’s exactly the purpose it was made for? Kind of like “i need to remove a Robertson head screw, but i don’t want to use a Robertson bit - what can i do?”

The answer is one of two options, i think: either get comfortable with useEffect, or look into “Observable” libraries, triggering an effect when an observed variable changes…which would be doing the same thing as useEffect.

I’m not actually being snarky, just that you’re describing exactly the intended use of that. Is there a reason you’d prefer to not use it?

2 Likes

Thanks @snowmonkey for the quick reply and for suggestion as well. I think, I will try to take on the “Observable” part once, because “useEffect” is just not happening with me. I had worked on Angular, I will try to use it on React. I am just unable to grasp this react state management…

Thanks for the suggestion, I will look into that direction once.

1 Like

@mahesh.raddyx , sorry to be that guy, but useEffect is such a core part of React, that sooner or later you have to be comfortable with it.

In this case for example, you can define an effect for when the village changes.

useEffect(() => {
  // do something when village change.
  // remember to return a cleanup resource function.
console.log("Villages, changed. Time to do something")
}, [villages])

You can slowly get comfortable with it.

Also you can read a bit about fetching in useEffect here:

Hope this gives you some inspiration.
Good luck and happy coding.

1 Like

Thanks @Marmiz for your reply. I will definitely look into the link that you have provided. And I would really be happy to use the useEffect as it should be used in this case and also it is a part of React.

The problem is, “villages”, gets changed in many part of the view/component. And it gets difficult to track the change.

Like, there is a case when user selects a village by clicking on it to get the farmers list, for that I am adding an extra key to the “village object” called “is_clicked” which highlights the selected village in the list through css. This, I create another list of villages along with the selected village. Here, I will have to track things like selected village as well because it needs to passed to the fetchFarmers().

Then, it becomes clumsy and sometimes, also goes into infinite loop of useEffect. If there would be something like conditional calls, like sometime changing villages need not call farmers list and sometimes it is. Then, it would be great.

Any suggestion or wisdom regarding this issue will also be helpful

1 Like

Yeah, that is very important to React.

The problem is, “villages”, gets changed in many part of the view/component. And it gets difficult to track the change.

I’m not sure what you mean by “track the change”. You shouldn’t need to track it, just that the component render the current state of the data.

Like, there is a case when user selects a village by clicking on it to get the farmers list, for that I am adding an extra key to the “village object”

I hope that when you say “adding an extra key” you do not mean that you are mutating your villages array. Remember that React is looking for changes in that villages reference to know when to rerender. If you mutate that, it doesn’t know anything has changed.

Then, it becomes clumsy and sometimes, also goes into infinite loop of useEffect.

Then it is constructed incorrectly. You can also have logic in the useEffect callback to conditionally run, no problem.

…like sometime changing villages need not call farmers list and sometimes it is

Yes, that can work.


Yeah, the React hooks take a little getting used to, especially if you’re used to lifecycle methods. They are a different way of thinking. I might suggest taking a step back from your project and do some tutorials just on React hooks to get more comfortable.

1 Like

@kevinSmith thank you for your reply and the solution. I will take all the points into consideration.

And yes I am not mutation the array rather I always create a new array so that the reference gets changed so that react would know the change in state.

And I think I should have a deep dive on React hooks. Thanks for the suggestion.

1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.