While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.

React Hooks are a great new feature in React 16.8. Hooks are a feature that you’ll end up using every single day of your React development. Hooks are useful because they enable more features for developers. If you want to use state or lifecycle methods you would normally have to change to using React.Component and classes. Hooks let us use these features in functional components.

React’s State Hook

Let’s say we have a component like this:

State in Components

import React, { Component } from 'react';

class JustAnotherCounter extends Component {
  state = {
    count: 0
  };

  setCount = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <h1>{this.state.count}</h1>

        <button onClick={this.setCount}>Count Up To The Moon</button>
      </div>
    );
  }
}

With React Hooks, we are a able to condense that class into this functional component:

State with Functional Components and useState

import React, { useState } from 'react';

function JustAnotherCounter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={() => setCount(count + 1)}>Count Up To The Moon</button>
    </div>
  );
}

Notice how the functional component streamlines our code.

useState() syntax

You may be unfamiliar with the line with the useState() syntax. This uses destructuring assignment for arrays. This is similar to how we would pull props out an object with object destructuring.

Let’s compare object destructuring to array destructuring to see why the latter is helpful.

Object Destructuring

const users = { admin: 'chris', user: 'nick' };

// grab the admin and user but rename them to SuperAdmin and SuperUser
const { admin: SuperAdmin, user: SuperUser } = users;

Object destructuring requires more writing to grab a variable and rename it. With array destructuring we just name variables as we get them out of the array. First variable is the first item in the array.

Array Destructuring

// array destructuring
const users = ['chris', 'nick'];

// grab in order and rename at the same time
const [SuperAdmin, SuperUser] = users;

useState gives us two variables and we can name our two variables whatever we want. Just know that:

  1. The first variable is the value. Similar to this.state
  2. The second variable is a function to update that value. Similar to this.setState

The final part to useState is the argument that we pass to it. The useState argument is the initial state value. In the case of our counter, we started at 0.

The React Hooks intro gives a good section on this: Classes confuse both people and machines. The gist is classes can sometimes be confusing and can be written any number of ways. Dive into somebody else’s project and you could be in for a world of different syntax and style choices. Note that there are no plans to remove classes support. We just have another way to code

By allowing classes to be converted into smaller functional components, we can even further break out parts of our application into smaller and more focused components.

Using Multiple State Hooks

We can even use useState() multiple times in the same function.

import React, { useState } from 'react';

function AllTheThings() {
  const [count, setCount] = useState(0);
  const [products, setProducts] = useState([{ name: 'Surfboard', price: 100 }]);
  const [coupon, setCoupon] = useState(null);

  return <div>{/_ use all those things here _/}</div>;
}

React’s Effect Hook

The State Hook allows us to use state in React functional components. This gets us a step closer to using functional components over class components. The next part of moving to functional components is lifecycle methods. Effects are similar to componentDidMount, componentDidUpdate, and componentWillUnmount.

This is what the Effect Hook is for. Side-effects are things you want your application to make like:

  • Fetching data
  • Manually changing the DOM (document title)
  • Setting up a subscription

Effects will run after every render, including the first render.

Let’s compare a class to a functional component:

import React, { Component } from 'react';

class DoSomethingCrazy extends Component {
  componentDidMount() {
    console.log('i have arrived at the party!');
    document.title = 'preesent';
  }

  render() {
    return <div>stuff goes here</div>;
  }
}

When using the the Effect Hook, we use useEffect():

function DoSomethingCrazy() {
  useEffect(() => {
    console.log('i have arrived at the party!');
    document.title = 'preesent';
  });

  return <div>stuff goes here</div>;
}

useEffect() is similar to componentDidMount and componentDidUpdate.

Running an Effect Hook only when something changes

Since useEffect() runs every time a component renders, we can get it to only run once on mount. The Effect Hook can take a second argument, an array. It will look through the array and only run the effect if one of those values has changed.

componentDidMount: Runs once

// only run on mount. pass an empty array
useEffect(() => {
  // only runs once
}, []);

componentDidUpdate: Runs on changes

// only run if count changes
useEffect(
  () => {
    // run here if count changes
  },
  [count]
);

componentWillUnmount()

To run something before a component unmounts, we have to return a function from useEffect():

useEffect(() => {
  UsersAPI.subscribeToUserLikes();

  // unsubscribe
  return () => {
    UsersAPI.unsubscribeFromUserLikes();
  };
});

Using State and Effects Together

There’s no problem using them together. Together they can create functional components that work the same as your class components.

Here’s a more real-world example of a component that fetches a list of users from GitHub API with useEffect() and keeps them using useState(). We’ll start by using useState() for users:

Using State

import React, { useState } from 'react';

function GitHubUsers() {
  const [users, setUsers] = useState([]);
}

We are setting users as an empty array to start in useState([]). Next, we will bring in the useEffect() hook and use fetch to grab data from the GitHub API:

Using Effect

import React, { useState } from 'react';

function GitHubUsers() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    fetch('https://api.github.com/users')
      .then(response => response.json())
      .then(data => {
        setUsers(data); // set users in state
      });
  }, []); // empty array because we only run once
}

Notice we are setting the second argument for useEffect as an empty array so it only runs once. Finally, we will show the list.

Displaying Users

import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';

function GitHubUsers() {
  // ...other stuff here...

  return (
    <div className="section">
      {users.map(user => (
        <div key={user.id} className="card">
          <h5>{user.login}</h5>
        </div>
      ))}
    </div>
  );
}

We’ve also added Bulma CSS so it’s somewhat better looking than the default. That’s what the section and card classes are for:
screenshot of how the list looks with the Bulma CSS added

Conclusion

React State and Effect Hooks are wonderful additions to the library and will be tools to make it easier to learn React for new developers. A lot of Vue’s success is in its simplicity in creating components.

Now with React, you don’t have to differentiate between a class or whether to use a functional component.

0 Comments

Creative Commons License