Part 1: Crash Course on React Hooks

As of 2019, Dan Abramov and his team rocked the developing world by releasing version 16.8 of React. In short, the newest version of React introduces Hooks, which are functions that let you “hook” into React lifecycle and state using functional components. Hooks change how we write our components in a meaningful way. If you don’t believe me, check out the differences between code written in the old React versus the same code written with Hooks.

Old React (Left) vs New React with Hooks (Right)

As you can see with this simple example, Hooks change React quite a bit. Instead of a class component, now we have a much more concise functional component. How is this functional component storing state and what happened to the lifecycle methods? Why use these strange Hooks at all? Well, I’m glad you asked…

Why Use Hooks?

As most people that have used React for long enough can attest to, React is a wonderful library but has the penchant to become unwieldy. Even with state management libraries like Redux, React components can grow too large to follow easily. Stateful logic becomes difficult to reuse unless you implement higher-order components or render props, but these patterns can make your code challenging to restructure and read.

Class components can also grow cumbersome with lifecycle methods performing various pieces of logic. For example, componentDidMount might contain logic for two separate concerns but they are still grouped under the componentDidMount method. Meanwhile, one concern also has logic in componentShouldUpdate while the other requires cleanup in componentWillUnmount. Wouldn’t it be easier to keep the logic grouped by concern and not by lifecycle method?

Hooks change all of this by eliminating class components. Instead, Hooks let you store and change state in functional components. Don’t worry about lifecycle methods, because they aren’t going anywhere. With Hooks, we can now access lifecycle methods in functional components too! Lastly, Hooks let us reuse state logic more easily so we can avoid cumbersome workarounds like higher-order components and render prop patterns. This sounds great but how do you use Hooks?

Rules of Hooks

Before we dive deeper into this new React, you need to know the two fundamental rules of Hooks:

  1. Keep to the Top: although Hooks resemble Javascript functions, you can only call Hooks at the top level. You cannot call hooks inside of loops, conditions, or nested functions. This should make intuitive sense if you remember that in class components, state was defined separately and never defined inside of a loop for example.
  2. Only React Functional Components: you cannot call Hooks inside regular Javascript functions. The one exception is Custom Hooks that you write, but I’ll elaborate on that in next week’s Part 2.

Now that you know the rules, we can begin learning how to actually implement Hooks. There are two main inbuilt Hooks that React provides: State Hooks and Effect Hooks. There are other inbuilt Hooks, which I will explain in Part 2, but these two Hooks provide the main power of the new React. With State and Effect Hooks, functional components can now do so much more.

State Hooks

In the old version of React, we needed a class component to define state in the constructor. If we ever wanted to change state, we needed to call this.setState. Well now that we are eschewing class components, we have a new feature, useState, to access the state functionality in a functional component.

As you can see, useState is imported from React and is the Hook that makes the magic happen. useState takes in only one argument which sets up the initial value of its state. Then through destructuring, useState returns two things: the current state value (age) and a function (setAge) to update state. The function to update state is similar to the old this.setState, except this is not needed and more importantly, useState updates state with a new value. This is unlike this.setState, which merges a new value with the current state.

In the past, if you had multiple variables stored on state, they would all go within the this.state object. Now, we can store multiple variables by defining multiple State Hooks. This might seem like extra work, but keeping the different state variables separate will help us later when using Effect Hooks.

Effect Hooks

If you recall, I mentioned that Hooks can replicate the behavior of the lifecycle methods. Well, this is where Effect Hooks come into play. Like useState, useEffect is one of the inbuilt Hooks that React provides us. Simply, Effect Hooks serve the same role as componentDidMount, componentDidUpdate, and componentWillUnmount, but wrapped up under the same call.

In the code above, useEffect starts after changes are made to the DOM. The effects are run after every render, including the first render. For example, say the user changes the puppy’s name to “Spot”. This would change state and trigger useEffect to run. Additionally, useEffect can optionally return a function, which serves as the “clean up” or componentWillUnmount.

Like State Hooks, you can also have multiple Effect Hooks within a component. You simply define useEffect after its corresponding useState to pair the two Hooks together. Previously, lifecycle methods kept all sorts of logic in them related to various variables in state. Now, we can separate the logic inside lifecycle methods and organize them with their corresponding state logic. This makes our components easier to read and understand!

Conclusion

This is just a small tease on the benefits of React Hooks. With Hooks, we only need functional components which make our components less cumbersome. It will take some adjustment, but I hope after reading this, you are intrigued enough to try Hooks on your own. In Part 2, I will cover the less commonly used inbuilt Hooks and also creating your own Custom Hooks. See you then and happy coding!