Learn React Hooks

3 (2 reviews total)
By Daniel Bugl
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Introducing React and React Hooks

About this book

React Hooks revolutionize how you manage state and effects in your web applications. They enable you to build simple and concise React.js applications, along with helping you avoid using wrapper components in your applications, making it easy to refactor code.

This React book starts by introducing you to React Hooks. You will then get to grips with building a complex UI in React while keeping the code simple and extensible. Next, you will quickly move on to building your first applications with React Hooks. In the next few chapters, the book delves into various Hooks, including the State and Effect Hooks. After covering State Hooks and understanding how to use them, you will focus on the capabilities of Effect Hooks for adding advanced functionality to React apps. You will later explore the Suspense and Context APIs and how they can be used with Hooks. Toward the concluding chapters, you will learn how to integrate Redux and MobX with React Hooks. Finally, the book will help you develop the skill of migrating your existing React class components, and Redux and MobX web applications to Hooks.

By the end of this book, you will be well-versed in building your own custom Hooks and effectively refactoring your React applications.

Publication date:
October 2019
Publisher
Packt
Pages
426
ISBN
9781838641443

 

Introducing React and React Hooks

React is a JavaScript library that can be used to build efficient and extensible web applications. React was developed by Facebook, and is used in many large-scale web applications, such as Facebook, Instagram, Netflix, and WhatsApp Web.

In this book, we are going to learn how to build complex and efficient user interfaces with React, while keeping the code simple and extensible. Using the new paradigm of React Hooks, we can greatly simplify dealing with state management and side effects in web applications, ensuring the potential for growing and extending the application later on. We are also going to learn about React context and React Suspense, as well as how they can be used with Hooks. Afterward, we are going to learn how to integrate Redux and MobX with React Hooks. Finally, we are going to learn how to migrate from existing React class components, Redux, and MobX web applications, to React Hooks.

In the first chapter of this book, we are going to learn about the fundamental principles of React and React Hooks. We start by learning what React and React Hooks are, and why we should use them. Then, we move on to learn about the functionality of Hooks. Finally, we give an introduction to the kinds of Hooks that are provided by React, and a couple of Hooks that we are going to learn about throughout the book. By learning the fundamentals of React and React Hooks, we will be better able to understand the concepts that will be introduced in this book.

The following topics will be covered in this chapter:

  • Learning about the fundamental principles of React
  • Motivating the need for React Hooks
  • Getting started with React Hooks
  • Giving an overview of various Hooks
 

Technical requirements

fairly recent version of Node.js should already be installed (v11.12.0, or higher). The npm package manager for Node.js also needs to be installed.

The code for this chapter can be found on the GitHub repository: https://github.com/PacktPublishing/Learn-React-Hooks/tree/master/Chapter01.

Check out the following video to see the code in action:

http://bit.ly/2Mm9yoC

Please note that it is highly recommended that you write the code on your own. Do not simply run the code examples that were previously provided. It is important to write the code yourself in order to learn and understand it properly. However, if you run into any issues, you can always refer to the code example.

Now, let's get started with the chapter.

 

Principles of React

Before we start learning about React Hooks, we are going to learn about the three fundamental principles of React. These principles allow us to easily write scalable web applications. The fundamental principles are important to know, as they will help us to understand how and why Hooks fit into the React ecosystem.

React is based on three fundamental principles:

  • Declarative: Instead of telling React how to do things, we tell it what we want it to do. As a result, we can easily design our applications and React will efficiently update and render just the right components when the data changes. For example, the following code, which duplicates strings in an array is imperative, which is the opposite of declarative:
const input = ['a', 'b', 'c']
let result = []
for (let i = 0; i < input.length; i++) {
result.push(input[i] + input[i])
}
console.log(result) // prints: [ 'aa', 'bb', 'cc' ]

As we can see, in imperative code, we need to tell the computer exactly what to do, step by step. However, with declarative code, we can simply tell the computer what we want, as follows:

const input = ['a', 'b', 'c']
let result = input.map(str => str + str)
console.log(result) // prints: [ 'aa', 'bb', 'cc' ]

In the previous declarative code, we tell the computer that we want to map each element of the input array from str to str + str. As we can see, declarative code is much more concise.

  • Component-based: React encapsulates components that manage their own state and views, and then allows us to compose them in order to create complex user interfaces.
  • Learn once, write anywhere: React does not make assumptions about your technology stack, and tries to ensure that you can develop apps without rewriting existing code as much as possible.

We just mentioned that React is component-based. In React, there are two types of components:

  • Function components: JavaScript functions that take the props as an argument, and return the user interface (usually via JSX)
  • Class components: JavaScript classes that provide a render method, which returns the user interface (usually via JSX)

While function components are easier to define and understand, class components were needed to deal with state, contexts, and many more of React's advanced features. However, with React Hooks, we can deal with React's advanced features without needing a class component!

 

Motivation for using React Hooks

React's three fundamental principles make it easy to write code, encapsulate components, and share code across multiple platforms. Instead of reinventing the wheel, React always tries to make use of existing JavaScript features as much as possible. As a result, we are going to learn software design patterns that will be applicable in many more cases than just designing user interfaces.

React always strives to make the developer experience as smooth as possible, while ensuring that it is kept performant enough, without the developer having to worry too much about how to optimize performance. However, throughout the years of using React, a couple of problems have been identified. 

Let's take a look at these problems in detail in the following sections. 

Confusing classes

In the past, we had to use class components with special functions called life cycle methods, such as componentDidUpdate, and special state-handling methods, such as this.setState, in order to deal with state changes. React classes, and especially the this context, which is a JavaScript object, are hard to read and understand for both humans and machines.

this is a special keyword in JavaScript that always refers to the object that it belongs to:

  • In a method, this refers to the class object (instance of the class).
  • In an event handler, this refers to the element that received the event.
  • In a function or when standing alone, this refers to the global object. For example, in a browser, the global object is the Window object.
  • In strict mode, this is undefined in a function.
  • Additionally, methods such as call() and apply() can change the object that this refers to, so it can refer to any object.

For humans, classes are hard because this always refers to different things, so sometimes (for example, in event handlers) we need to manually rebind it to the class object. For machines, classes are hard, because the machines do not know which methods in a class will be called, and how this will be modified, making it hard to optimize performance and remove unused code.

Furthermore, classes sometimes require us to write code in multiple places at once. For example, if we want to fetch data when the component renders, or the data updates, we need to do this using two methods: once in componentDidMount, and once in componentDidUpdate.

To give an example, let's define a class component that fetches data from an Application Programming Interface (API):

  1. First, we define our class component by extending the React.Component class:
class Example extends React.Component {
  1. Then, we define the componentDidMount life cycle method, where we pull data from an API:
        componentDidMount () {
fetch(`http://my.api/${this.props.name}`)
.then(...)
}
  1. However, we also need to define the componentDidUpdate life cycle method in case the name prop changes. Additionally, we need to add a manual check here, in order to ensure that we only re-fetch data if the name prop changed, and not when other props change:
    componentDidUpdate (prevProps) {
if (this.props.name !== prevProps.name) {
fetch(`http://my.api/${this.props.name}`)
.then(...)
}
}
}
  1. To make our code less repetitive, we could define a separate method called fetchData, in order to fetch our data, as follows:
        fetchData () {
fetch(`http://my.api/${this.props.name}`)
.then(...)
}
  1. Then, we could call the method in componentDidMount and componentDidUpdate:
        componentDidMount () {
this.fetchData()
}

componentDidUpdate (prevProps) {
if (this.props.name !== prevProps.name) {
this.fetchData()
            }
}

However, even then we still need to call fetchData in two places. Whenever we update arguments that are passed to the method, we need to update them in two places, which makes this pattern very prone to errors and future bugs.

Wrapper hell

Before Hooks, if we wanted to encapsulate state management logic, we had to use higher-order components and render props. For example, we create a React component that uses contexts to deal with user authentication as follows:

  1. We start by importing the authenticateUser function in order to wrap our component with the context, and the AuthenticationContext component in order to access the context:
import authenticateUser, { AuthenticationContext } from './auth'
  1. Then, we define our App component, where we make use of the AuthenticationContext.Consumer component and the user render prop:
const App = () => (
<AuthenticationContext.Consumer>
{user =>
  1. Now, we display different texts depending on whether the user is logged in or not:
                user ? `${user} logged in` : 'not logged in'

   Here, we used two JavaScript concepts:

    • A ternary operator, which is an inline version of the if conditional. It looks as follows: ifThisIsTrue ? returnThis : otherwiseReturnThis.
    • A template string, which can be used to insert variables into a string. It is defined with backticks (`) instead of normal single quotes ('). Variables can be inserted via the ${variableName} syntax. We can also use any JavaScript expressions within the ${} brackets, for example, ${someValue + 1}.
  1. Finally, we export our component after wrapping it with the authenticateUser context:
        }
</AuthenticationContext.Consumer>
)

export default authenticateUser(App)

In the previous example, we used the higher-order authenticateUser component to add authentication logic to our existing component. We then used AuthenticationContext.Consumer to inject the user object into our component through its render props.

As you can imagine, using many contexts will result in a large tree with many sub-trees, also called wrapper hell. For example, when we want to use three contexts, the wrapper hell looks as follows:

<AuthenticationContext.Consumer>
{user => (
<LanguageContext.Consumer>
{language => (
<StatusContext.Consumer>
{status => (
...
)}
</StatusContext.Consumer>
)}
</LanguageContext.Consumer>
)}
</AuthenticationContext.Consumer>

This is not very easy to read or write, and it is also prone to errors if we need to change something later on. Furthermore, the wrapper hell makes debugging hard, because we need to look at a large component tree, with many components just acting as wrappers.

Hooks to the rescue!

React Hooks are based on the same fundamental principles as React. They try to encapsulate state management by using existing JavaScript features. As a result, we do not need to learn and understand specialized React features anymore; we can simply tap into our existing JavaScript knowledge in order to use Hooks.

Using Hooks, we can solve all the previously mentioned problems. We do not need to use class components anymore, because Hooks are simply functions that can be called in function components. We also do not need to use higher-order components and render props for contexts anymore, because we can simply use a Context Hook to get the data that we need. Furthermore, Hooks allow us to reuse stateful logic between components, without creating higher-order components.

For example, the aforementioned problems with life cycle methods could be solved using Hooks, as follows:

function Example ({ name }) {
useEffect(() => {
fetch(`http://my.api/${this.props.name}`)
.then(...)
}, [ name ])
// ...
}

The Effect Hook that was implemented here will automatically trigger when the component mounts, and whenever the name prop changes.

Furthermore, the wrapper hell that was mentioned earlier could also be solved using Hooks, as follows:

    const user = useContext(AuthenticationContext)
const language = useContext(LanguageContext)
const status = useContext(StatusContext)

Now that we know which problems Hooks can solve, let's get started using Hooks in practice!

 

Getting started with React Hooks

As we can see, React Hooks solve many problems, especially of larger web applications. Hooks were added in React 16.8, and they allow us to use state, and various other React features, without writing a class. In this section, we are going to start out by initializing a project with create-react-app, then we will define a class component, and finally we will write the same component as a function component using Hooks. By the end of this section, we will have talked about the advantages of Hooks, and how we would go about migrating to a Hook-based solution.

Initializing a project with create-react-app

To initialize a React project, we can use the create-react-app tool, which sets up the environment for React development, including the following:

  • Babel, so that we can use the JSX and ES6 syntaxes
  • It even includes language extras beyond ES6, such as the object spread operator, which we are going to make use of later
  • Additionally, we could even use TypeScript and Flow syntax

Furthermore, create-react-app sets up the following:

  • Autoprefixed Cascading Style Sheets (CSS), so that we do not need browser-specific prefixes such as -webkit
  • A fast interactive unit test runner with code coverage reporting
  • A live development server, which warns us about common mistakes
  • A build script, which bundles JavaScript, CSS, and images for production, including hashes and sourcemaps
  • An offline-first service worker and a web app manifest to meet all criteria of a Progressive Web App (PWA)
  • Hassle-free updates for all the tools that have been previously listed

As we can see, the create-react-app tool makes React development a lot easier for us. It is the perfect tool for us to use in order to learn about React, as well as for deploying React applications in production.

Creating a new project

In order to set up a new project, we run the following command, which creates a new directory named <app-name>:

> npx create-react-app <app-name>
If you prefer using the yarn package manager, you can run yarn create react-app <app-name> instead.

We are now going to create a new project using create-react-app. Run the following command to create a new React project for the first example of the first chapter:

> npx create-react-app chapter1_1

Now that we have initialized our project, let's move on to starting the project.

Starting a project

In order to start a project in development mode, we have to run the npm start command. Run the following command:

> npm start

Now, we can access our project by opening http://localhost:3000 in our browser:

Our first React app!

As we can see, with create-react-app, it is quite easy to set up a new React project!

Deploying a project

To build a project for production deployments, we simply run the build script:

  1. Run the following command to build the project for production deployment:
> npm run-script build
Using yarn, we can simply run yarn build. Actually, we can run any package script that does not conflict with the name of an internal yarn command in this way: yarn <script-name>, instead of npm run-script <script-name>.
  1. We can then serve our static build folder with a web server, or by using the serve tool. First, we have to install it:
> npm install -g serve
  1. Then, we can run the serve command, as follows:
> serve -s build
The -s flag of the serve command rewrites all not-found requests to index.html, allowing for client-side routing.

Now, we can access the same app by opening http://localhost:5000 in our browser. Please note that the serve tool does not automatically open the page in your browser.

After learning about create-react-app, we are now going to write our first component with React.

Starting with a class component

First, we start out with a traditional React class component, which lets us enter a name, which we then display in our app.

Setting up the project 

As mentioned before, we are going to use create-react-app to initialize our project. If you have not done so already, run the following command now:

> npx create-react-app chapter1_1

Next we are going to define our app as a class component.

Defining the class component

We first write our app as a traditional class component, as follows:

  1. First, we remove all code from the src/App.js file.
  2. Next, in src/App.js, we import React:
import React from 'react'     
  1. We then start defining our own class component—MyName:
class MyName extends React.Component {
  1. Next, we have to define a constructor method, where we set the initial state object, which will be an empty string. Here, we also need to make sure to call super(props), in order to let the React.Component constructor know about the props object:
    constructor (props) {
super(props)
this.state = { name: '' }
}
  1. Now, we define a method to set the name variable, by using this.setState. As we will be using this method to handle input from a text field, we need to use evt.target.value to get the value from the input field:
   handleChange (evt) {
this.setState({ name: evt.target.value })
}
  1. Then, we define the render method, where we are going to display an input field and the name:
   render () {
  1. To get the name variable from the this.state object, we are going to use destructuring:
       const { name } = this.state

The previous statement is the equivalent of doing the following:

       const name = this.state.name
  1. Then, we display the currently entered name state variable:
    return (
<div>
<h1>My name is: {name}</h1>
  1. We display an input field, passing the handler method to it:
                <input type="text" value={name} onChange={this.handleChange} />
</div>
)
}
}
  1. Finally, we export our class component:
export default MyName

If we were to run this code now, we would get the following error when entering text, because passing the handler method to onChange changes the this context:

Uncaught TypeError: Cannot read property 'setState' of undefined
  1. So, now we need to adjust the constructor method and rebind the this context of our handler method to the class:
    constructor (props) {
super(props)
this.state = { name: '' }
this.handleChange = this.handleChange.bind(this)
}
There is the possibility of using arrow functions as class methods, to avoid having to re-bind the this context. However, to use this feature we need to install the Babel compiler plugin, @babel/plugin-proposal-class-properties, as it is not a released JavaScript feature yet.

Finally, our component works! As you can see, there is a lot of code required to get state handling to work properly with class components. We also had to rebind the this context, because otherwise our handler method would not work. This is not very intuitive, and is easy to miss while developing, resulting in an annoying developer experience.

Example code

The example code can be found in the Chapter01/chapter1_1 folder.

Just run npm install in order to install all dependencies, and npm start to start the application; then visit http://localhost:3000 in your browser (if it did not open automatically).

Using Hooks instead

After using a traditional class component to write our app, we are going to write the same app using Hooks. As before, our app is going to let us enter a name, which we then display in our app.

Please note that it is only possible to use Hooks in React function components. You cannot use Hooks in a React class component!

We now start by setting up the project.

Setting up the project

Again, we use create-react-app to set up our project:

> npx create-react-app chapter1_2

Let's get started with defining a function component using Hooks now.

Defining the function component

Now, we define the same component as a function component:

  1. First, we remove all code from the src/App.js file.
  2. Next, in src/App.js, we import React, and the useState Hook:
    import React, { useState } from 'react'
  1. We start with the function definition. In our case, we do not pass any arguments, because our component does not have any props:
    function MyName () {

The next step would be to get the name variable from the component state. However, we cannot use this.state in function components. We have already learned that Hooks are just JavaScript functions, but what does that really mean? It means that we can simply use Hooks from function components, just like any other JavaScript function!

To use state via Hooks, we call useState() with our initial state as the argument. This function returns an array with two elements:

    • The current state
    • A setter function to set the state
  1. We can use destructuring to store these two elements in separate variables, as follows:
            const [ name, setName ] = useState('')

The previous code is equivalent to the following:

            const nameHook = useState('')
const name = nameHook[0]
const setName = nameHook[1]
  1. Now, we define the input handler function, where we make use of the setName setter function:
            function handleChange (evt) {
setName(evt.target.value)
}
As we are not dealing with classes now, there is no need to rebind this anymore!
  1. Finally, we render our user interface by returning it from the function. Then, we export the function component:
    return (
<div>
<h1>My name is: {name}</h1>
<input type="text" value={name} onChange={handleChange} />
</div>
)
}

export default MyName

And that's it—we have successfully used Hooks for the first time! As you can see, the useState Hook is a drop-in replacement for this.state and this.setState.

Let's run our app by executing npm start, and opening http://localhost:3000 in our browser:

Our first React app with Hooks

After implementing the same app with a class component and a function component, let's compare the solutions.

Example code

The example code can be found in the Chapter01/chapter1_2 folder.

Just run npm install in order to install all dependencies, and npm start to start the application; then visit http://localhost:3000 in your browser (if it did not open automatically).

Comparing the solutions

Let's compare our two solutions, in order to see the differences between class components, and function components using Hooks.

Class component

The class component makes use of the constructor method in order to define state, and needs to rebind this in order to pass the handler method to the input field. The full class component code looks as follows:

import React from 'react'

class MyName extends React.Component {
constructor (props) {
super(props)
this.state = { name: '' }

this.handleChange = this.handleChange.bind(this)
}

handleChange (evt) {
this.setState({ name: evt.target.value })
}

render () {
const { name } = this.state
return (
<div>
<h1>My name is: {name}</h1>
<input type="text" value={name} onChange={this.handleChange} />
</div>
)
}
}

export default MyName

As we can see, the class component needs a lot of boilerplate code to initialize the state object and handler functions.

Now, let's take a look at the function component.

Function component with Hook

The function component makes use of the useState Hook instead, so we do not need to deal with this or a constructor method. The full function component code looks as follows:

import React, { useState } from 'react'

function MyName () {
const [ name, setName ] = useState('')

function handleChange (evt) {
setName(evt.target.value)
}


return (
<div>
<h1>My name is: {name}</h1>
<input type="text" value={name} onChange={handleChange} />
</div>
)
}

export default MyName

As we can see, Hooks make our code much more concise and easier to reason about. We do not need to worry about how things work internally anymore; we can simply use state, by accessing the useState function!

Advantages of Hooks

Let's remind ourselves about the first principle of React:

Declarative: Instead of telling React how to do things, we tell it what we want it to do. As a result, we can easily design our applications, and React will efficiently update and render just the right components when the data changes.

As we have learned in this chapter, Hooks allow us to write code that tells React what we want. With class components, however, we need to tell React how to do things. As a result, Hooks are much more declarative than class components, making them a better fit in the React ecosystem.

Hooks being declarative also means that React can do various optimizations on our code, since it is easier to analyze functions and function calls rather than classes and their complex this behavior. Furthermore, Hooks make it easier to abstract and share common stateful logic between components. By using Hooks, we can avoid render props and higher-order components.

We can see that Hooks not only make our code more concise, and are easier to reason about for developers, but they also make the code easier to optimize for React.

Migrating to Hooks

Now, you might be wondering: does that mean class components are deprecated, and we need to migrate everything to Hooks now? Of course not—Hooks are completely opt-in. You can try Hooks in some of your components without rewriting any of your other code. The React team also does not plan on removing class components at the moment.

There is no rush to migrate everything to Hooks right now. It is recommended that you gradually adopt Hooks in certain components where they will be most useful. For example, if you have many components that deal with similar logic, you can extract the logic to a Hook. You can also use function components with Hooks side by side with class components.

Furthermore, Hooks are 100% backward-compatible, and provide a direct API to all the React concepts that you already know about: props, state, context, refs, and life cycle. Furthermore, Hooks offer new ways to combine these concepts and encapsulate their logic in a much better way that does not lead to wrapper hell or similar problems. We are going to learn more about this later in the book.

The Hooks mindset

The main goal of Hooks is to decouple stateful logic from rendering logic. They allow us to define logic in separate functions and reuse them across multiple components. With Hooks, we do not need to change our component hierarchy in order to implement stateful logic. There is no need to define a separate component that provides the state logic to multiple components anymore, we can simply use a Hook instead!

However, Hooks require a completely different mindset from classic React development. We should not think about the life cycle of components anymore. Instead, we should think about data flow. For example, we can tell Hooks to trigger when certain props or values from other Hooks change. We are going to learn more about this concept in Chapter 4, Using the Reducer and Effect Hooks. We should also not split components based on life cycle anymore. Instead, we can use Hooks to deal with common functionalities, such as fetching data, or setting up a subscription.

Rules of Hooks

Hooks are very flexible. However, there are certain limitations to using Hooks, which we should always keep in mind:

  • Hooks can only be used in function components, not in class components
  • The order of Hook definitions matters, and needs to stay the same; thus, we cannot put Hooks in if conditionals, loops, or nested functions

We are going to discuss these limitations in more detail, as well as how to work around them, throughout this book.

 

Overview of various Hooks

As we learned in the previous section, Hooks provide a direct API to all React concepts. Furthermore, we can define our own Hooks in order to encapsulate logic without having to write a higher-order component, which causes a wrapper hell. In this section, we are going to give an overview of various Hooks, which we are going to learn about throughout the book.

Hooks provided by React

React already provides various Hooks for different functionalities. There are three basic Hooks, and a handful of additional Hooks.

Basic Hooks

Basic Hooks provide the most commonly needed functionalities in stateful React apps. They are as follows:

  • useState
  • useEffect
  • useContext

Let's take a look at each of these in the following sections.

useState

We have already used this Hook. It returns a stateful value (state) and a setter function (setState) in order to update the value.

The useState Hook is used to deal with state in React. We can use it as follows:

import { useState } from 'react'

const [ state, setState ] = useState(initialState)

The useState Hook replaces this.state and this.setState().

useEffect

This Hook works similarly to adding a function on componentDidMount and componentDidUpdate. Furthermore, the Effect Hook allows for returning a cleanup function from it, which works similarly to adding a function to componentWillUnmount.

The useEffect Hook is used to deal with effectful code, such as timers, subscriptions, requests, and so on. We can use it as follows:

import { useEffect } from 'react'

useEffect(didUpdate)

The useEffect Hook replaces the componentDidMountcomponentDidUpdate, and componentWillUnmount methods.

useContext

This Hook accepts a context object and returns the current context value.

The useContext Hook is used to deal with context in React. We can use it as follows:

import { useContext } from 'react'

const value = useContext(MyContext)

The useContext Hook replaces context consumers.

Additional Hooks

Additional Hooks are either more generic variants of basic Hooks or are needed for certain edge cases. The additional Hooks we are going to look at are as follows:

  • useRef
  • useReducer
  • useMemo
  • useCallback
  • useLayoutEffect
  • useDebugValue

Let's dive deeper into these additional Hooks in the following sections.

useRef

This Hook returns a mutable ref object, where the .current property is initialized to the passed argument (initialValue). We can use it as follows:

import { useRef } from 'react'

const refContainer = useRef(initialValue)

The useRef Hook is used to deal with references to elements and components in React. We can set a reference by passing the ref prop to an element or a component, as follows: <ComponentName ref={refContainer} />

useReducer

This Hook is an alternative to useState, and works similarly to the Redux library. We can use it as follows:

import { useReducer } from 'react'

const [ state, dispatch ] = useReducer(reducer, initialArg, init)

The useReducer Hook is used to deal with complex state logic.

useMemo

Memoization is an optimization technique where the result of a function call is cached, and is then returned when the same input occurs again. The useMemo Hook allows us to compute a value and memoize it. We can use it as follows:

import { useMemo } from 'react'

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])

The useMemo Hook is useful for optimization when we want to avoid re-executing expensive operations.

useCallback

This Hook allows us to pass an inline callback function, and an array of dependencies, and will return a memoized version of the callback function. We can use it as follows:

import { useCallback } from 'react'

const memoizedCallback = useCallback(
() => {
doSomething(a, b)
},
[a, b]
)

The useCallback Hook is useful when passing callbacks to optimized child components. It works similarly to the useMemo Hook, but for callback functions.

useLayoutEffect

This Hook is identical to useEffect, but it only fires after all Document Object Model (DOM) mutations. We can use it as follows:

import { useLayoutEffect } from 'react'

useLayoutEffect(didUpdate)

The useLayoutEffect Hook can be used to read information from the DOM.

Use the useEffect Hook when possible, because useLayoutEffect will block visual updates and slow down your application.

Finally, we are going to take a look at the last Hook provided by React at the time of writing.

useDebugValue

This Hook can be used to display a label in React DevTools when creating custom Hooks. We can use it as follows:

import { useDebugValue } from 'react'

useDebugValue(value)

Make sure to use this Hook in custom Hooks to display the current state of your Hooks, as it will make it easier to debug them.

Community Hooks

In addition to all the Hooks that React provides, there are already plenty of libraries that have been published by the community. These libraries also provide Hooks. The Hooks we are going to look into are as follows:

  • useInput
  • useResource
  • useDimensions
  • Navigation Hooks
  • Life cycle Hooks
  • Timer Hooks

Let's see an overview of what these Hooks are in the following sections.

useInput

This Hook is used to easily implement input handling, and to synchronize the state of an input field with a variable. It can be used as follows:

import { useInput } from 'react-hookedup'

function App () {
const { value, onChange } = useInput('')

return <input value={value} onChange={onChange} />
}

As we can see, Hooks greatly simplify dealing with input fields in React.

useResource

This Hook can be used to implement asynchronous data loading via requests in our application. We can use it as follows:

import { useRequest } from 'react-request-hook'

const
[profile, getProfile] = useResource(id => ({ url: `/user/${id}`, method: 'GET' })

As we can see, using a special Hook for dealing with fetching data is quite simple.

Navigation Hooks

These Hooks are part of the Navi library, and are used to implement routing via Hooks in React. The Navi library provides many more routing-related Hooks. We are going to learn about routing via Hooks, in depth, later on in the book. We can use them as follows:

import { useCurrentRoute, useNavigation } from 'react-navi'

const { views, url, data, status } = useCurrentRoute()
const { navigate } = useNavigation()

As we can see, Hooks make routing much easier to deal with.

Life cycle Hooks

The react-hookedup library provides various Hooks, including all life cycle listeners for React.

Please note that it is not recommended to think in terms of a component life cycle when developing with Hooks. These Hooks just provide a quick way to refactor existing components to Hooks. However, when developing new components, it is recommended that you think about data flow and dependencies, rather than life cycles.

Here, we list two of them, but the library actually provides many more Hooks, which we will learn about later on. We can use the Hooks provided by react-hookedup as follows:

import { useOnMount, useOnUnmount } from 'react-hookedup'

useOnMount(() => { ... })
useOnUnmount(() => { ... })

As we can see, Hooks can directly replace life cycle methods in class components.

Timer Hooks

The react-hookedup library also provides Hooks for setInterval and setTimeout. These work similarly to calling setTimeout or setInterval directly, but as a React Hook, which will persist between re-renders. If we directly defined timers in our function component without Hooks, we would be resetting the timer every time the component re-renders.

We can pass the time in milliseconds as a second argument. We can use them as follows:

import { useInterval, useTimeout } from 'react-hookedup'

useInterval(() => { ... }, 1000)
useTimeout(() => { ... }, 1000)

As we can see, Hooks greatly simplify how we deal with intervals and timeouts in React.

Other community Hooks

As you can imagine, there are many more Hooks that are provided by the community. We will learn about the previously mentioned community Hooks in depth, and various other community Hooks in Chapter 8: Using Community Hooks.

 

Summary

In this first chapter of the book, we started out by learning the fundamental principles of React and which types of components it provides. We then moved on to learning about common problems with class components, and using existing features of React, and how they break the fundamental principles. Next, we implemented a simple application using class components and function components with Hooks, in order to be able to compare the differences between the two solutions. As we found out, function components with Hooks are a much better fit for React's fundamental principles, as they do not suffer from the same problems as class components, and they make our code much more
concise and easy to understand! Finally, we got our first glimpse of the various Hooks that we are going to learn about throughout this book. After this chapter, the basics of React and React Hooks are clear. We can now move on to more advanced concepts of Hooks.

In the next chapter, we are going to gain an in-depth knowledge of how the State Hook works, by reimplementing it from scratch. By doing so, we are going to get a grasp on how Hooks work internally, and what their limitations are. Afterward, we are going to create a small blog application using the State Hook!

 

Questions

To recap what we have learned in this chapter, try answering the following questions:

  1. What are React's three fundamental principles?
  2. What are the two types of components in React?
  3. What are the problems with class components in React?
  4. What is the problem of using higher-order components in React?
  1. Which tool can we use to set up a React project, and what is the command that we need to run to use it?
  2. What do we need to do if we get the following error with class components: TypeError: undefined is not an object (evaluating 'this.setState')?
  3. How do we access and set React state using Hooks?
  4. What are the advantages of using function components with Hooks, in comparison to class components?
  5. Do we need to replace all class components with function components using Hooks when updating React?
  6. What are the three basic Hooks that are provided by React?
 

Further reading

If you are interested in more information about the concepts that we have learned in this chapter, take a look at the following reading material:

About the Author

  • Daniel Bugl

    Daniel Bugl is a developer, product designer, and entrepreneur focusing on web technologies. He has a Bachelor of Science degree in business informatics and information systems and is now studying data science at the Vienna University of Technology (TU Wien). He is a contributor to many open source projects and a member of the React community. He also founded and runs his own hardware/software start-up, TouchLay, which helps other companies present their products and services. At his company, he constantly works with web technologies, particularly making use of React and React Hooks.

    Browse publications by this author

Latest Reviews

(2 reviews total)
The download didn't work for weeks
Concise explanations, if you are looking for a book to learn React, this is not the most appropriate book. But, to know the new basic Hooks of React. It would have been nice if the author had delved deeper into the Hooks API.

Recommended For You

Professional JavaScript

Develop your JavaScript programming skills by learning strategies and techniques commonly used in modern full-stack application development

By Hugo Di Francesco and 3 more
The JavaScript Workshop

Cut through the noise and get real results with a step-by-step approach to beginner JavaScript development

By Joseph Labrecque and 7 more
Mastering JavaScript Functional Programming - Second Edition

Explore the functional programming paradigm and the different techniques for developing better algorithms, writing more concise code, and performing seamless testing

By Federico Kereki
Hands-On Docker for Microservices with Python

A step-by-step guide to building microservices using Python and Docker, along with managing and orchestrating them with Kubernetes

By Jaime Buelta