DEV Community

Cover image for πŸ›‘ STOP thinking about React lifecycle methods.
Swastik Yadav
Swastik Yadav

Posted on • Updated on

πŸ›‘ STOP thinking about React lifecycle methods.

In this post let's talk about the paradigm shift from lifecycle methods to state synchronization and hooks in ReactJs.

Here is a video version of this post, if that's what you prefer.

When class components were a thing in ReactJs (Well it still is, but no one likes them anymore), we use to think a lot in terms of mouting, unmounting, and lifecycle methods.

lifecycle diagram

Whenever a class component mounts, the lifecycle methods are called in following sequence: constructor β†’ render β†’ DOM and refs update β†’ componentDidMount

But then came React Hooks, and we started to think in terms of dependency array.

And, often times we ask:

What is the hooksΒ equivalentΒ toΒ [some lifecycle method]?

The quick answer is that hooks are a paradigm shift from thinking in terms of "lifecycles" to thinking in terms of "state and synchronization with DOM".

lifecycles!=hoooks

Trying to take the old paradigm and apply it to hooks just doesn't work out very well and can hold you back.

useEffect(fn) // fn invoked on all updates

useEffect(fn, []) // invoked on mount

useEffect(fn, [a, b, c]) // invoked if any of the members of the array are updated
Enter fullscreen mode Exit fullscreen mode

The above snippet is not the right way to think about React hook.

Lifecycles are gone, but we still think of useEffect with empty dep array as componentDidMount, and that’s not the right way to think about React Hooks.

Now I want to present to you the right way to think about react hooks.

State Synchronization

See, the question is not "when does this effect run" the question is "which state does this effect synchronizes with"

useEffect(fn) // useEffect with no dep array, sync with all state

useEffect(fn, []) // useEffect with empty dep array, sync with no state

useEffect(fn, [stateA, stateB]) // useEffect with stateA and stateB in dep array sync with stateA and stateB.
Enter fullscreen mode Exit fullscreen mode

And that’s how you should think about React Hooks.


Hope, you found this video useful, and if so, make sure show your support by subscribing.

I also run a weekly newsletter, so you can join me there also: https://www.getrevue.co/profile/8020lessons

Thank You!

Discussion (16)

Collapse
lukeshiru profile image
Luke Shiru

One important thing to remember is that we should avoid useEffect as much as possible. Generally if you’re using it to keep state in sync, is a sign there is something wrong with the architecture of your component or app. Almost always there is a better solution than using side-effects, so if you think the solution for your current issue is a useEffect, you might have to think a little bit longer ☺️

Cheers!

Collapse
swastikyadav profile image
Swastik Yadav Author • Edited on

Well, the whole point to ReactJs is to keep the UI and State in sync. And useEffect is the most commonly used hook to handle side-effects in ReactJs community.

useEffect can create performance issue without dependency array, but with dep array, I think it works just fine.

Would love to know your view on this, if you are ok to elaborate your point a little bit more.

Thank You πŸ™

Collapse
lukeshiru profile image
Luke Shiru

The point is not so much "You should not use useEffect" is more like "You should avoid useEffect", or "You shouldn't default to useEffect". You're correct when you say that is the "most common hook for side-effects", but the thing is that also we should avoid side effects as much as possible. There are several scenarios in which folks use useEffect incorrectly (focus elements when they could use autoFocus, getting input values when they could just use useState or even useRef, and so on), but the problem with that hook is that the more you have in your app, the worst your app will behave.

I recently wrote a similar comment in a similar post about useEffect, and my recommendation is to take a look at React's new docs about side effects and the WIP docs about useEffect which go into more detail, but the long story short is that you should avoid it, and even in some scenarios where useEffect was useful, we'll be getting a new core hook called useEvent so it will be even less recommended then.

Thread Thread
swastikyadav profile image
Swastik Yadav Author • Edited on

Ah! Now I got your point. Now I see where you coming from.

I missUnderstood your point of miss-using the useEffect hook.

useEffect

Thread Thread
lukeshiru profile image
Luke Shiru

Yup. I agree with your initial point of not thinking in lifecycle methods, mainly because is the wrong mental model. My point was mainly that the solution is not to just replace that logic with side effects, but actually rethink the component so you don’t need either lifecycle methods or side effects (both are bad). As you just shared in the screenshot, it should be a last resource.

Thread Thread
swastikyadav profile image
Swastik Yadav Author • Edited on

Agreed

So, how would you go about making an API call, based on the response of which your view will be rendered.

As per my React knowledge useEffect is the only way here.

Please share if it can be done without useEffect.

Thread Thread
lukeshiru profile image
Luke Shiru

You can get some insights in this Dan Abramov's tweet from a thread made when he published the docs for useEffect. Some folks had a similar reaction to yours, and his suggestion is to use a framework or external library for stuff like API calls.

I personally would use react-query in general projects, or (like I did on my personal website) I would use remix. The react-query approach is quite elegant:

const Example = () => {
    const { data = [], isLoading } = useQuery(getUsers);

    return isLoading ? (
        <span>Loading...</span>
    ) : (
        <ul>
            {data.map(({ id, name }) => (
                <li key={id}>{name}</li>
            ))}
        </ul>
    );
};
Enter fullscreen mode Exit fullscreen mode

Compared to the way you'll do it with useEffect:

const Example = () => {
    const [loading, setLoading] = useState(true);
    const [data, setData] = useState([]);

    useEffect(
        () =>
            void getUsers()
                .then(setData)
                .finally(() => setLoading(false)),
        [],
    );

    return loading ? (
        <span>Loading...</span>
    ) : (
        <ul>
            {data.map(({ id, name }) => (
                <li key={id}>{name}</li>
            ))}
        </ul>
    );
};
Enter fullscreen mode Exit fullscreen mode

You can see that is way less idiomatic, and unnecessarily verbose. You'll see in that same tweet thread that you can use useEffect if you want to do it "raw", but you don't have any caching strategies, you have a waterfall loading effect instead of being parallel, and much more issues that are resolved if you just use a framework or library for stuff like API interactions.

Thread Thread
swastikyadav profile image
Swastik Yadav Author • Edited on

Wow, this is really very insightful. I will give this a thorough study.

Thanks for sharing this.

And thanks for starting this positive and constructive conversation.

😊

Thread Thread
z2lai profile image
z2lai • Edited on

This short and succinct article was one of the most enlightening ones I've read about the useEffect hook. I've subscribed to your Youtube channel and newsletter, can't wait to see more from you!

It can't be a coincidence that you wrote this just a few days after David Khourshid's (creator of XState library) talk about this exact topic, which include the same insights in this comment thread. If you haven't checked it out, you really should as I believe you'll benefit a lot from it, and many of David's talks: youtube.com/watch?v=HPoC-k7Rxwo

His conclusion is the same as Luke's - avoid useEffect hook as side-effects should be considered as part of state management ([state, event]=>[nextState, effects]) and not separately, which is what external libraries help you do. This is one of the things that David's own XState library does on top of implementing a declarative and explicit way of managing state with State Machines. You should also check out his talks on state machines and his XState library.

Thread Thread
swastikyadav profile image
Swastik Yadav Author

Thanks for all your support.

I will surely check David Khourshid's talk on this topic.

Collapse
k_penguin_sato profile image
K-Sato

Nicely explained!

Collapse
swastikyadav profile image
Swastik Yadav Author

Thanks for the kind words K-Sato 😊

Collapse
oumaymasghayer profile image
Oumayma JavaScript Developer

Thank you for clearing it up!

Collapse
swastikyadav profile image
Swastik Yadav Author

My pleasure... πŸ™

Collapse
andrewbaisden profile image
Andrew Baisden

Nice article.

Collapse
swastikyadav profile image
Swastik Yadav Author

Thank you, Andrew 😊