Cool kids handle state with Hooks

Anssam Ghezala
7 min readJul 2, 2019

Co-written by Amir Ghezala and Anssam Ghezala

A React application is basically a set of React components put together to serve the application’s purpose. These components can be either functional or classes. Functional components are functions that receive props (properties) and return JSX code that is rendered to the screen. They are categorized as stateless components because they do not utilize state and lifecycle methods.

However, prior to 16.8, if you wanted to have a state in your component or wanted to use life-cycle methods, you would need to make your component as a class-based one. Using both types of components has its own advantages when creating an application. However, conversion between them is really annoying and knowing which lifecycle to use, when and how to use it correctly is really challenging when it comes to complex applications.

React 16.8 introduces a new feature: hooks. React hooks are a fundamental change since they make it finally possible to create stateful (with state) function components!

This writeup aims to showcase the current state of state management in React. We will take the example of a simple calculator app and implement it using class components logic, then using two different React Hooks: useState and useReducer. By doing so, we will go through state manipulation in both class and function components.

The final result of our calculator app will look as follow:

Calculator gif

The calculator accepts two input numbers to performs arithmetic operations according to the selected operator.

Class component

I- Using a class component

To remind you again, we resorted to the class-based type component to create our App in order to catch the user inputs and update the state values accordingly. The state of our app consisted of the following:

  • firstnumber: the Number 1 user input,
  • secondnumber: the Number 2 user input,
  • operator: the operator the user chooses,
  • result: the final result of computing Number 1 and Number 2 with the operator.
State of the Calculator

We also had our onChange and onClick handlers that call this.setState to update the dynamic stored values in this.state:

  • firstNumUpdate: function that updates the state value firstnumber according to the Number 1 user input,
  • secondNumUpdate: function that updates the state value secondnumber according to the Number 2 user input,
  • operatorUpdate: function that updates the state value operator according to the operator user selection.
  • executeComputation: function that computes the result depending on the Number 1, Number 2 and the chosen operator.
Action listeneres

All in all, our class component’s return method looks like this:

Calculator app as a class component :)

That’s it for our class component! You can check out the code here:

Now that we’ve seen how our calculator looks like as a class component, let’s implement it using hooks.

II- Using a functional component

a) Using the useState hook

Let’s now implement the same application using a functional component and the useState hook. We can’t use the this.state or this.setState properties anymore because we wont use a class-based component. However, our functional component with the help of hooks will store and update the state. As mentioned before, hooks are React helper functions to create & manipulate the state of your component.

First let’s import useState from React.

import React, { useState } from "react";

We then write our App class-based component as a functional component using the following syntax:

function App() {

We then call the useState hook function that takes an initial state for the user input and returns an array of two elements:

UseState() hook
  • The first element of the array is the state of the object,
  • The second element is a function that is used to update that state.

For the initial state we can pass anything, an empty string, 0, null, an empty array, an empty object, whatever kind of state you want to manage initially.

const [state, setState] = useState(initialState);

In our case we decide to put the initial value as “0” for the first number, second number and result input elements, while the operator select input element takes an initial value of “+”.

We can of course use a single useState call and have all our state (including the numbers, the result, and the operator) in a single object. However, the advisable way is to use multiple calls so you can separate your states, change them independently and focus on one state at a time.

When an event is triggered (e.g. the onChange event of the first number input), we use its corresponding state updater function to perform a state update.

setState reference function

Voilà 🎉! Checkout how our calculator App looks like now:

b) Using the useReducer hook

useState is not the only hook we can use to manipulate our component state. We will see now another hook, useReducer, which helps achieve the same result with a different syntax. This hook uses a reducer with two arguments: a state and an action and returns a new state of the app. If you’ve ever used Redux state management library, you will find the useReducer hook very familiar to Redux’s reducer.

useReducer takes a function (called a reducer) which has 2 arguments: the state and an action. Depending on the action passed to the reducer, a new state of the app is returned. We’ll come back to the reducer in a bit.

Step1: Configuring the useReducer

We first import the useReducer:

import React, { useReducer } from "react";

We then define the hook like so:

const [state, dispatch] = useReducer(reducer, initialState);

Step2: Defining the logic for the user input

Let’s look at our problem again: we wish to add, subtract, multiply or divide 2 numbers. To do that, the user first inputs the 2 numbers. So let’s take a look at our Number 1 and Number 2 input fields.

Since the complexity of the tree is not that high and the data of the user input doesn’t need to be passed from a component to another embedded one, we could add a useState hook, as we did above, just to manipulate the user input. However, for the sake of the example, let’s use useReducer for everything, that is, for handling the user input and the logic of the calculator.

We define two actions: FIRST_NUM_UPDATE and SECOND_NUM_UPDATE in our reducer, representing the actions to be dispatched or “triggered” when the user inputs Number 1 or Number 2 respectively:

FIRST_NUM_UPDATE and SECOND_NUM_UPDATE actions :)

The inputted values for firstnumber or secondnumber are passed through the action parameter. Depending on which number was inputted, FIRST_NUM_UPDATE or SECOND_NUM_UPDATE are then dispatched to return a new state containing the newly inputed values of firstnumber and secondnumber.

Now that our reducer handles these actions, let’s actually trigger them whenever the user changes the inputs for the first and second numbers.

firstNumUpdate and secondNumUpdate helpers

We know that we want to dispatch them during the onChange of Number 1 and Number 2 input fields. So let’s call firstNumUpdate and secondNumUpdate in the onChange handler for each number input field as such:

Number 1 and Number 2 input fields

Now we have successfully used our reducer to update the state to whatever the user inputs in the number input fields! Let’s do the same to our operator select element:

  • We define the OPERATOR_UPDATE action to return the selected operator in our reducer function
‘OPERATOR_UPDATE’ action
  • We define a helper method operatorUpdate to dispatch the OPERATOR_UPDATE action:
operatUpdate() helper method
  • We call operatorUpdate from our onChange handle in our operator select element:
Operator select element

Cool, now let’s get our hands dirty with the calculator’s logic!

Step3: Defining the logic for the calculator

Our calculator gives the user the ability to add, subtract, multiply or divide two numbers. Just from stating the problem we already have 4 reducer actions !

  • ADD action representing the sum of our numbers
‘ADD’ action
  • SUBTRACT action representing the subtraction of our numbers:
‘SUBTRACT’ action
  • MULTIPLY action representing the multiplication of our numbers:
‘MULTIPLY’ action
  • DIVIDE action representing the division of our numbers:
‘DIVIDE’ action

Ultimately, our reducer function looks like this:

Final reducer function

We then define our helper method executeComputation to dispatch those actions depending on which operator is used:

ExecuteAction function

Now we just need to display the result simply using state.result:

Display of final result !

And we’re done 🎉! You can check out what we just did here:

Conclusion

According to the React documentation, if you are already using class components, you don’t have to switch to hooks. However, you no longer have to use classes just to have state in your component. The useState and useReducer React hooks provide a nice syntax to achieve the create & manipulate state in a function component.

An important notice concerning the rules of using React hooks.

Hooks are used at the top level of your component, for example; you can’t call the hook function nested in another function , or in an if statement or in a loop. Moreover, they have to be component functions that take props and returns JSX.

Some other cool ones to look at would be:

  • useContext: Accepts a React.createContext context object and returns the current context value for that context.
  • useEffect: Similar to componentDidMount and componentDidUpdate.
  • useCallback: Returnes a memoized callback.

To read more about Hooks, checkout the Hooks API.

Did you like this article? Was it helpful? Do you have any suggestions to improve it? If you have any thoughts or comments, we would love to hear them!

Notice: My brother Amir Ghezala and I are both learning React and publish articles every month. Follow us on twitter @amir_ghezala and @anssam_ghezala to get in touch! :)

📝 Read this story later in Journal.

👩‍💻 Wake up every Sunday morning to the week’s most noteworthy stories in Tech waiting in your inbox. Read the Noteworthy in Tech newsletter.

--

--

Anssam Ghezala

Soft. Eng. student @McGill exploring the web one framework at a time!