Rundown of the Most Important React Hooks
Comparing speed and performance of functional and class-based components
Hooks solve a wide variety of seemingly unconnected problems in React that we’ve encountered over five years of writing and maintaining tens of thousands of components.
Whether you’re learning React, use it daily, or even prefer a different library with a similar component model, you might recognize some of these problems.
Prerequisite for React Hooks
Hooks are a new addition to React 16.8. It is not available prior to this version. A little knowledge about React is enough to understand React Hooks.
Why React Hooks
We’ve often had to maintain components that started out simple but grew into an unmanageable mess of stateful logic and side effects.
Each lifecycle method often contains a mix of unrelated logic. For example, components might perform data fetching in
However, the same
componentDidMount method might also contain some unrelated logic that sets up event listeners, with cleanup performed in
Mutually related code that changes together gets split apart but completely unrelated code ends up combined in a single method. This makes it too easy to introduce bugs and inconsistencies.
In many cases, it’s not possible to break these components into smaller ones because the stateful logic is all over the place. It’s also difficult to test them. This is one of the reasons many people prefer to combine React with a separate state management library.
However, that often introduces too much abstraction, requires you to jump between different files, and makes reusing components more difficult.
To solve this, Hooks let you split one component into smaller functions, based on which pieces are related (such as setting up a subscription or fetching data), rather than forcing a split based on lifecycle methods.
You may also opt into managing the component’s local state with a reducer to make it more predictable.
Hooks are lightning-fast
Hooks are very fast because if you create two components, one is a functional component that uses Hooks to manage state and the other is a class-based component.
We are going to make a basic counter in both components to compare their speed and performance. The first one is a class-based component, which simply performs a counter logic.
We checked the performance of this class-based component using audits in Chrome developer tools and it turns out to be 95%.
Using Hooks in a functional component increases the performance to 98% which is 3% more than that of a class-based component.
We use the simple logic of the counter and it shows a difference of 3%. And, if the logic in the component is big, the performance difference is much more.
There are lots of React Hooks including
useDebugValue, and you can create your own custom Hooks.
We are going to run through some of them and compare them with a class-based component without Hooks.
We’ve already seen a basic example of
useState Hooks in the counter logic above.
useState Hooks return an array in which the first element is the state name and the second one is a function to modify the state value. In
useState, we pass the initial value of the state.
const [count , setCount] = useState(0)
This is how React Hooks manage state to store values similarly to class-based components.
The code for functional components is way smaller than that of class-based components. The same logic can be performed with the class-based component, as follows:
You can see that React Hooks minimize the code to almost half of the simple counter logic, compared to the class-based component.
useEffect Hook is used to handle the lifecycle method in a functional component.
If you’re familiar with the React class lifecycle methods, you can think of the
useEffect Hook as
getDerivedStateFromProps combined as a beginner.
It helps to write the logic in one place itself. But Dan Abramov has repeated many times that
useEffect shouldn’t be introduced as an alternative to these lifecycle methods only.
If you use
useEffect with that mental model, you’ll get confused later. Instead, he suggests thinking of
useEffect as a place where you run side-effects when a value in the dependency array changes.
useEffect is a callback function where we can give the second element as dependency array, which can contain anything like variables, props, state, etc., on which we have to run
There are two common kinds of side effects in React components — those that don’t require cleanup and those that do.
This is a basic example of using
componentDidUpdate using a class-based component, which changes the title of the page based on the count value. This is an extension of the previous count logic.
This is how we can perform the same logic with Hooks. It decreases the code length almost to half and increases efficiency as well.
The dependency array comes into the picture when we have more than one state and we have to use the
useEffect Hook only on a particular state change.
In the below example, we have two state counts and names and we have to update the document title only when our count value changes. That’s why a dependency array contains only
Earlier, we looked at how to express side effects that don’t require any cleanup. However, some effects do.
For example, we might want to set up a subscription to an external data source. In that case, it is important to clean up so that we don’t introduce a memory leak!
For a cleanup function like
componentWillUnmount, every effect may return a function that cleans up after it.
Refer to this example, which uses
useEffect Hooks to count the time left for the next day in HH:MM:SS format.
Accepts a context object (the value returned from
React.createContext) and returns the current context value for that context.
The current context value is determined by the
value prop of the nearest
<MyContext.Provider> above the calling component in the tree.
const value = useContext(MyContext)
When the nearest
<MyContext.Provider> above the component updates, this Hook will trigger a re-render with the latest context
value passed to that
If you’re familiar with the context API before Hooks,
useContext(MyContext) is equivalent to
static contextType = MyContext in a class, or to
useContext(MyContext) only lets you read the context and subscribe to its changes. You still need a
<MyContext.Provider> above in the tree to provide the value for this context.
An alternative to
useState. Accepts a reducer of type
(state, action) => newState and returns the current state paired with a
dispatch method. (If you’re familiar with Redux, you already know how this works.)
useReducer is usually preferable to
useState when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one.
useReducer also lets you optimize performance for components that trigger deep updates because you can pass dispatch down instead of callbacks.
There are two different ways to initialize the
useReducer state. You may choose either one depending on the use case. The simplest way is to pass the initial state as a second argument and the next one is by lazily.
If you need to cache the result of an invoked function,
useMemo comes into the picture. It is helpful in performance optimization.
useMemo is a Hook that will only recompute the cached value when one of the dependencies has changed. This optimization leads to avoiding expensive calculations on every render.
In the above example, because of
isEven operation will only happen when
counterOne is incremented.
useMemo was not there, it would happen even if
counterTwo was changed and it decreases the efficiency as we add a heavy operation in the
In the future, React may choose to “forget” some previously memoized values and recalculate them on the next render, e.g. to free memory for offscreen components.
Write your code so that it still works without
useMemo — and then add it to optimize performance.
If you need to cache a function,
useCallback comes into the picture. It is also used for performance optimization.
Building your own Hooks lets you extract component logic into reusable functions.
use and who may call other Hooks. For a complete understanding of custom Hooks refer to this documentation.
I hope you enjoyed reading my first article.