The React Component Lifecycle Methods: And How They Translate Into React Hooks
I’m on a bit of a React journey at the moment, so I’ve decided to write some blog posts about its key concepts. First on my list is the component lifecycle, which I’ve recently had to get my teeth stuck into!
This article provides an explanation of some of the most useful Lifecycle methods, before showing how to translate these methods into React Hooks.
What is the React component Lifecycle?
Just like humans, React components go through their own lifecycles. These lifecycles are composed of several different phases that can be manipulated to run code at different times in the component’s existence. Each phase comes with its own lifecycle methods, which are used to run code at specific times in the program.
The lifecycle methods come in four main categories:
3. Error Boundaries
You could say that mounting constitutes the components birth, unmounting its death, and everything in between as its growth. First, the component is created and mounted to the DOM. Once in place it can undergo updates triggered by changes to
props, before unmounting itself from the DOM.
The Constructor( )
constructor() is the first method invoked during the component lifecycle. It's automatically called to initialise state and bind any event handlers in a class component. Assuming that you already know how to use the constructor in a React class component, here’s a quick example:
The most important thing to know about the constructor (in the context of React lifecycle) is that it is NOT the place to introduce any *side effects. The same goes for
Render() which is a pure function, meaning that you can't alter state or perform any asynchronous functions within it. This is where the other lifecycle methods come in handy.
*Side Effects: Anything that happens outside of the return value. API calls, logging to the console and calling setTimeout() are examples of side effects, as they live beyond the execution of the return value.
ComponentWillMount( ) (Deprecated)
ComponentWillMount() used to be the next lifecycle method and was called just before the
render() method. React have now deprecated its use due to it often being used unsafely.
It might have been tempting to initiate an AJAX requests here, to give the API call a head start while the UI loads. It's generally a bad idea to do this, since it can result in errors.
Best practice is to render the HTML before sending a data request, as it allows the skeleton UI to load and provide a loading indicator to show the user that the page is on its way. Similarly, if you have an app with data that changes every few seconds, you don’t want a change in the data to cause a re-render every time it updates.
The next lifecycle method is
componentDidMount(), which runs immediately after the
render() is complete and the component has mounted to the DOM. It is the best location for initiating an asynchronous function. Here's a basic example of how you could fetch data in a class component:
Data Fetching with React Hooks
With the release of React 16.8, side-effects such as data fetching don’t have to be placed under lifecycle methods in a ‘stateful’ class component. React Hooks were introduced to allow developers to tap into the React state and lifecycle features without using class components. Hooks provide a more concise means of setting state and side-effects in a function component.
useEffect() hook can be used in an equivalent way to
componentWillUnmount(). In other words, it handles side effect functions. Here's the example above refactored to React Hooks:
We just want
useEffect() to run and clean up once, so a dependency array can be passed in as the second argument. This array can either be empty, or it can contain parameters (state and props) that control when the
useEffect() is run.
If the array is left empty, then it'll only run once on mounting. If you include dependency parameters, the
useEffect() hook will run each time one of these parameters is changed or updated. Without the dependency conditions, it can be triggered by any change to the component's data, which can be quite often if you have a complex app with lots of props.
If you’ve got state based on props you might need to use the
componentDidUpdate() method, which is invoked straight after an update has occurred. Use it to update the DOM by comparing the previous props to the current props, see the example below:
Don’t forget to unmount!
The useEffect hook also offers an optional clean-up function called
componentWillUnmount(), which runs just before the component unmounts. You can use this method to unsubscribe from any side effects or async functions initiated in
componentDidMount(). Leaving active subscriptions results in a memory leak warning, so it's important to use this function to destroy anything that might continue running after the component has left the DOM.
Here’s an example of a function that gets called every time the user scrolls. The
useEffect() still only mounts and unmounts once, so our cleanup function
removeEventListener cancels the event subscription when the component unmounts.
Error boundaries are a bit different as they can only be used in class components, and can’t be used with Hooks. Error boundaries are class components that use either (or both of)
static getDerivedStateFromError() or
componentDidCatch() to catch errors in their child component tree. They catch errors, log the error, and provide a fallback UI (for example a retry button) instead of breaking the whole app:
Once defined, they can be used as a regular component:
For a more in depth guide to all the lifecycle methods check out the React official docs.
Originally published at http://github.com.