Lifecycle Methods Using Hooks, or Why You Should Start Using useEffect Hook. React

Ali Toshmatov
3 min readMar 7, 2021

Ok, this is my first ever article, so love to hear your feedbacks and open to correct my mistakes.

Migrating from class-based components to functional components can be pretty painful, especially when you heavily rely on lifecycle methods. But fear no more, it is pretty straightforward than it might look. Although some lifecycle methods can’t be accessed in functional components, which I will talk about later, this article covers the most used and popular ones.

useEffect() is the only hook that we need to access lifecycle functionalities and it is imported from react. This hook gets function for the first argument and array of dependencies for the second argument. These dependencies decide whether the function which passed as a first argument should be called or not for each render. Also, you can write as many useEffect hooks as you want.

useEffect(()=>{
//code
}, [dep1, dep2])

These dependencies might be state or prop values. Every render useEffect makes a shallow comparison between old and new values of its dependencies, and if any of these values are changed, the function in the first argument is fired.

For instance, in the example below we are firing a new request every time our search or page states change:

useEffect(()=>{
fetchArticle({page: page, limit: 10, search: search})
}, [search, page])

Enough exploring useEffect, let's get how exactly we are going to use useEffect to replicate lifecycle methods.

componentDidMount() method is fired when the component is mounted on the DOM. This method is mainly used for fetching data from the backend or subscribe to some kind of data-stream.

componentDidMount(){
fetchArticles({page: 1, limit: 10});
}

Using useEffect it is pretty simple you just pass the function you want to get called and empty array of dependency and you are good to go. How it actually works is that any useEffect is called at least one time after the component is mounted on the DOM. So after calling our function for the first time, our useEffect has no dependency hence it won’t be called again.

useEffect(() => {
fetchArticles({ page: 1, limit: 10 });
}, []);

componentDidUpdate() method is called every time component rerenders meaning that any state or props changes.

componentDidUpdate(){
renderCount++;
}

As we discussed above you can customize your useEffect hooks to listen to changes of specific state or prop values and take actions based on them. But if you want fully Kamikaze with your component you can just drop the second argument in useEffect and it does the same thing as the componentDidUpdate method.

useEffect(()=>{
renderCount++;
})

componentWillUnmount(), last but not least, this method is often used to unsubscribe from data streams which might cause memory leaks if not closed on time.

componentWillUnmount(){
unsubscribeAuth();
}

This one might seem tricky, but it is very easy to use. You just need to return a function inside a function you passed in useEffect. And returned function gets called before the component unmounted from DOM.

useEffect(() => {
return () => {
unsubscribeAuth();
};
}, []);

Other lifecycle methods

There are still some more lifecycle methods that we can’t replicate using react hooks and keep in mind that they are only used in rare use cases. Like shouldComponentUpdate() which makes it easy to skip unnecessary renders or componentDidCatch(e) which is used to set up error boundaries. If you really need these methods you would better use class components.

--

--