A hands-on guide to transition to React hooks. Let’s get you hooked!
Are you still using class-based React components? Did you never have the chance to use React Hooks? You are not alone, although React hooks have been there for a while, some developers haven’t got around to using them yet.
In this article, we will show you how class-based components translate to React hooks. We will also go into detail for each hook and explain its capabilities using code samples and exercises. At the end of this article, you should become a master of the basic React hooks.
Are you ready to dive into hooks? Let’s go!
Make sure to follow along with the examples and create them into a demo react app. The more hands-on experience the more you’ll get used to the syntax and concepts.
React class-based component
Let’s first take a look at a simple class-based component and see how to translate this to using hooks.
This is a typical class-based component. Let’s take a look at the building blocks for a functional component. Instead of having a class, we will have one function which will handle everything. Instead of having a
render method separately, this function will now be your new
Functional components template
That’s how easy it is, it’s similar to a render method that receives the props as a parameter. An often-used way to make your props more readable is to destructure them using the spread operator, as follows.
This way, we can clearly see which props we expect. If we do this in combination with TypeScript, this could make the React
React state hooks
Since we are working with functions, we don’t really have
this available as it used to be in class-based components. To solve this issue, React came up with
hooks . These are pieces of code that can be used within your functional component to access the previously available concepts.
For the case of the state, we can use React’s
useState hook. If you are interested, here’s the official React documentation on useState. First, let’s define the useState variable as defined in the documentation.
You will immediately notice the useState syntax looks quite strange. It is because we are immediately destructuring it. The useState hook returns an array containing two items. The first item is the
value of the state variable. The second item is the
setter method for the state variable. Say, we want to update the headingText value in the state, then we can use the variable returned in the second item for this. Here’s an example:
How would this look like with multiple state variables? For each of the state variables, we’ll need to use the
Also important to note, is that we always passed a string to the
useState method. UseState will use this as the default value for the state variable, so this does not have to be a string, it could be a boolean, an object, or anything you’d like.
Exercise: useState — Implementing a click counter with hooks
If we look back at the previous example, we see how the state can be used, but the state is not particularly useful in this example. Let’s complete an exercise on useState together!
Let’s create a click counter with the useState hook in a functional component. The component should render a button. Every time the button is pressed, a paragraph should show the number of clicks on the button. You’ll have to keep the number of clicks in the state. Use the
Also, implement a prop that will set the initial amount of clicks to a specified value. If
20 is given to the component, then the component should show
20 clicks from the beginning.
Once ready, scroll down below the image to find the solution.
Here’s the solution:
Did you encounter any difficulties? Let us know in the comments!
React lifecycle and useEffect
We now know how to create functional components, and use the
useState hook. But what about lifecycle events?
Using the class-based
componentDidUpdate function, we could listen to changes in props of a component. How would we do this with hooks?
That’s where the
useEffect hook comes in. Whenever the value of a dependency has changed, it will trigger a given function. This hook does not return an array, instead, it allows you to run specific code when specific variables change during execution.
useEffect expects two parameters. The first one being the function to be run, the second parameter being the dependency list. The dependency list is a list of variables. Whenever any of these variables are changed, the given function in the first parameter will be run.
Remember in class-based React, we also had a function
componentDidMount ? Whenever the component is mounted on the page, the function would run. With
useEffect we need to provide a dependency list, so it is not suitable for replacing
componentDidMount right? Not exactly! It has a trick up its sleeves.
If we pass an empty list as a dependency list, the function given as the first parameter will be run in a similar way as
componentDidMount . Let’s try it out and extend our previous click-counter example! Note that the empty list is mandatory for this behavior. A common mistake from developers is to forget to define the list at all. If
undefined is given instead of
 , then the
useEffect will not behave like
React Context hook
The third and final hook classified as
basic by the React team is the
context hook. This hook allows you to pass data from the top of your application to all recursive children. This is often useful for creating providers, such as theme providers, so every component has access to the app’s theme style.
Do note, while we can pass down the context using the
useContext hook, we cannot update it! If this is needed for your application, then you will probably have to look at a state manager such as Redux instead.
We will not go into too many details on this hook, but here is an example usage from the React documentation, along with annotations:
React useMemo hook: performance optimization
React provides us the
useMemo hook to improve the performance of applications. The
useMemo hook accepts two arguments, similar to
useEffect : a function to execute, and a dependency list. One difference with
useEffect is that this hook will return the value of the function, so its value can be used within the functional component.
UseMemo will cache the value of the method, as long as the dependency list does not change. This means the method to calculate the value will not be run unless one of the values in the dependency list changes.
This is especially useful when working with variables by reference. If an array is defined in your functional component, the reference will keep changing on re-render. If this array is then passed on to children components, these will keep on re-rendering, when this is in fact not needed.
useMemo , we can avoid this behavior by caching the array and its reference until one of its dependencies for calculating its value changes. Let’s take a look at an example.
For pass by reference variables, useMemo can be useful to avoid re-rendering sub-components on every render of our main component. This is because we are caching the variable reference instead of redefining it on every render. Is this the only reason to use
useMemo ? Not exactly. It can be very useful for large processing.
Take a look at my article Should You UseMemo in React? A Benchmarked Analysis to find out exactly when you should be using
useMemo in your React applications.
View more about the useMemo hook at the official documentation page.
React useCallback hook
The useCallback hook is similar to the
useMemo hook, but instead of memoizing values of variables, it memoizes functions. It works on the same concept, in order to avoid the reference of the function changing on every render, cache the function until one of its dependencies change.
This avoids unnecessary re-renders from children components that receive this function as a prop.
React hooks list
The above-explained hooks are some of the more important hooks to use in React. React does have more hooks, here’s a list of hooks per type, as defined by React in the official documentation.
useStatefor managing the state of a component
useEffectfor lifecycle events of a component and triggering specific functions if specific dependencies change
useContextin order to pass down a context to all sub-components
useMemofor memoizing variable values
useCallbackfor memoizing functions
useReducerfor creating and using custom reducers
useReffor defining refs to components in the DOM
useImperativeHandlecan be used for customizing the value returned by useRef
useEffectbut only fires after all DOM updates
useDebugValueused for displaying debug data when developing custom hooks
Anybody can create additional hooks for React. Redux, a popular React state manager has created the
useSelector hook in order to retrieve Redux state data from within the functional components. If you have Redux already setup, retrieving the Redux data using this hook is a piece of cake.
Hooks Cheat Sheet
const [value, setter] = setState(defaultValue);
useEffect: usage for didMount
const myValue = useMemo(calculateFunction, dependencyList);
const myFunction = useMemo(callbackFunction, dependencyList);
const result = useSelector(state => state.item);
A current trend in React development is to move to using hooks. Hooks and class-based components are interoperable and compatible! You could have newer components made as functional components while keeping the older components class-based.
Do not worry, however, React is not going to remove class-based components any time soon.
There are no plans to remove classes from React - we all need to keep shipping products and can't afford rewrites. - React Team
Practice, and practice! The more you get hands-on experience with hooks, the faster you’ll get used to them. Create some pet-projects using React hooks. It’s fun, and you’ll get a nice project out of it!
Stay tuned for the next article regarding React hooks, in which we will create our own custom React hooks!