Exploring React Hooks, Part 1: useState & useEffect

Teamer Tibebu
5 min readDec 14, 2020

If you are a React beginner, you are most likely using class components all around in your code and have most likely noticed that, at times, it can be incredibly difficult to keep up with, update, and render your states. For myself, I had a difficult time keeping track of the dreaded “this”! Along with that, class components come with a lot of boilerplate code that are necessary to their functionality, such as constructors and binding.

Before React hooks, we weren’t able to use state in functional components, so if you had a beautifully constructed functional component that all of a sudden needed to manage state, you were stuck with refactoring that functional component into a class component. Now that hooks allow us to do so, that means less code compared to class components, making our code more readable and easier to follow. An added bonus of using hooks alongside functional components is that it removes the need to worry about binding our functions and remembering what “this” refers to. Woo Hoo! 🕺🏿

In the scope of this article, we will explore two of the major hooks in React, namely useState and useEffect, and understand how we can use them to work hand-in-hand with our functional components to make for, what I believe is, better and more readable React code. We will also explore some examples of how we would use hooks to achieve the same outcome of their class component counterparts. So without further ado, let’s dive in!

Managing State with Hooks

The most commonly used and easiest hook to understand in React is the useState hook, so we’ll begin there. As I stated above, before the advent of hooks, we needed to use class components in order to manage state, but with hooks, we no longer need to. Let’s take a look at the image below…

If you are familiar with using class components, you probably have a good grasp of what’s going on in the above image. Basically, this class component has a state, count, that is initialized with a value of 0. Every time the button on line 16 is clicked, our count state is incremented by a value of 1, and this state, when updated, will cause the component to re-render it’s value in the paragraph tag on line 15. Pretty straightforward example; now let’s take a look at how this could be accomplished by making use of the useState hook.

If we take a look at this image from top to bottom, the first thing you should notice is that we are importing useState, on line 1, from the React library. Secondly, and probably the most important thing to understand here, is occurring on line 4.

  1. Let’s start with the initial value. With the useState hook, the initial value that you wish to begin with, should be placed within its parenthesis. If you wish, you can ignore the initial value and set it to null (for example useState()). Keep in mind that unlike with classes, the initial state here does not have to be an object.
  2. We also see that we have destructured two variables from useState, the first, count, is the variable that will hold the state. You can access the state by using this variable directly.
  3. The second variable being destructured from useState, setCount, is the function that is used to set the state to another value.

It’s important to note here that “count” and “setCount” are both arbitrary names and could have been called whatever our hearts desired; they are simply variable names.

If you look further down in the image, you’ll notice that on line 8, instead of using this.state.count, we can access the variable directly, and on line 9, we use the setCount function to change the state of count in place of “this.setState({count: this.state.count + 1})”. Lastly, keep in mind that you can use as many states inside your functional component as your heart desires.

So all in all, our code is noticeably less clunky because we no longer need to make use of the constructor and “this”. Now let’s take a look at another important React hook, useEffect.

useEffect

The useEffect hook allows us to run side effects in functional components. As stated earlier, we don’t have access to React’s lifecycle methods when using functional components, so for many use cases, we can use the useEffect hook as an alternative.

What are Side Effects?

In React-y terms, a side effect is when a component’s variables or state change based on some outside thing, such as when a component receives new props that change its state or makes an API call and does something with the response.

If we look on line 1 again, we first import the useEffect function from the React library in order to make use of it. This hook acts similar to the lifecycle methods componentDidMount(), componentDidUpdate(), and componentWillMount().

Running useEffect on Each Render

The hook takes a function as its first argument. By default, and in the example above, the useEffect hook runs on the initial render and every re-render. So for every re-render of our component, we are updating the title of the page to the supplied phrase which makes use of the count state.

Note here that if we instead chose to update our state inside of the useEffect, we would have found ourselves in an infinite loop until our browser crashed. The reason for this is because useEffect runs after every render cycle finishes, and updating a state within it would cause an additional re-render, which would then cause the useEffect to run, which would cause the state to update again, which would cause the useEffect to run, and so on and so forth.

Running useEffect Only on Initial Render

Now you may be asking yourself, “what if I only want to call useEffect once, on the initial render?” Say we want to fetch data from an API, we don’t want this happening every time the component re-renders. Well there’s a way to accomplish that as well. The most common way to do this is by supplying useEffect a second argument, an empty array.

So if take the example from before where we updated the title of the document on every render and added an empty array as the second argument of useEffect, it would now only run on the initial render.

Running useEffect on State Change

You can also tell useEffect to “watch” for a change in a state variable and run only when that change occurs.

In the image above, we can see that we have two separate states, count and value. Because count is being passed into the array, the useEffect will only be run when that state changes, no matter how many times value changes.

Conclusion

I hope this article was at least a little helpful in understanding the useState and useEffect hooks. I know change can be uncomfortable and scary at times, but I challenge you to practice using these hooks as part of your React code in the future. In part two of this article, we will look deeper into the useEffect hook and explore a few more hooks, namely, useLayoutEffect and useReducer. Until then, practice practice practice!

--

--