Consider two versions of the same (very simple) app, with two pieces of state. A count variable and a random color. Whenever someone clicks a button, the counter should increment, and whenever the counter increments, the background-color should change. Version 1 without useEffect, where handleCount increments the counter, and also, while it’s at it, changes the color:
I often come across situations like this where I have to decide whether I want to useEffect or not. Are there any reasons why one is preferrable over the other, what’s the real advantage of useEffect? In this simple example, it doesn’t seem to make any difference beyond personal preference.
Well, consider this as a team coding thing. Would the counter dev team be expected to handle the implementation of a color switcher? What bearing does that have on their dev?
This is, clearly, a side effect. The main effect is incrementing counter. That should be pure, simply doing what it does. Then, if something else triggers a side effect from that change, the effect is “decoupled” from the main event. They work together, but through interfacing rather than one implementing the other.
I get what you’re saying, but since I’m the only developer in my team, it’s my decision. I was just wondering if there’s something inherently preferrable of useEffect beyond readability/maintainability/purity of functions. I think I’d just like to chat about this a little to have some different perspectives.
When you do the second method you will be causing a second distinct re-render whereas in the first react will probably do those things at the same time which is for efficiency.
useEffect diverges from class based react because you don’t need to attach everything regarding a re-render to a single method, but rather you can have multiple useEffect s for code that share a purpose, and this was done for separation of concerns, and that is done to make your code less error prone.
Sure, and it’s a good conversation. There’s nothing inherently wrong with writing an increment, and writing a paint, and them writing one function to manage them. That was my dev style for a long time, and on smaller projects, it’s easier to keep straight - you manage what happens when.
As projects grow, it’s an approach that can become an obstacle, as more and more parts change things without knowing where the change came from.
React has an ideology of how it is to be used, and they say if you follow this you will make readable code that is not prone to errors, but if you do not they cannot guarantee the efficacy of their library if you don’t use it how they intended.
React certainly talks about how to use, and when to use useEffect, and you can choose to this ignore this, but your implementation can be just as important and breaking.
I think your useEffect version is more declarative and the other one is more imperative.
The way I have heard it explained from more experienced developers is to look at useEffect as synchronizing state. Dan Abramov also has a very detailed article on useEffect worth checking out.
If you are only writing code for you to read, then I guess you should use the version you like the best. But writing code “just for you” for a long time might net you some bad habits as well. I would suggest always coding as if others had to read it and/or use it.
This sums up precisely the issues I have, when trying to make the decision which way to go. It’s like I have the choice between writing bad code in one way (less readable/pure), or writing bad code in another way (less performant).
It’s not just about theorising, I’m working on a project that involves a lot of API calls, so it’s crucial to optimise in that regard. It seems like moving on from simple calculator React Apps to something more complex is quite a task. Especially if you also want to make sure that you’ll still see through your code in 6 months.