React Hooks are a great new feature coming in React 16.7. React 16.6 brought some awesome new things like React.memo() and React.lazy and Suspense. The React team isn't stopping there.

Hooks are a feature that you'll end up using every single day of your React development. You can give them a try in React 16.7.0-alpha right now and are being discussed in an open RFC. Hooks are great because we get more tools as React 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!

What are Hooks?

React Hooks are a way to add React.Component features to functional components. Features like:

  • State
  • Lifecycle

Hooks let you use React's features without classes.

Don't worry though, classes aren't being removed or discouraged. We're being given more ways to code!

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>
  );
}

Here's a CodeSandbox for the above example:

Notice how much easier the functional component would be for beginners just learning React.

What is this 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 vs array destructuring to see why the array way is helpful. Object destructuring requires more writing to grab a variable and rename it.

Object Destructuring

// object destructuring. lots of writing!
const users = { admin: 'chris', user: 'nick' };

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

That bottom line can be a bit difficult to read. 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;

What does useState() give us?

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.

What's wrong with classes?

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.

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>;
}

And the CodeSandbox for this example:

useEffect() is... effectively 😏... similar to componentDidMount and componentDidUpdate

Running an Effect Hook only when something changes

Since useEffect() runs every time a component renders, how do we 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]
);

What about componentWillUnmount()

To run something before a component unmounts, we just 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>
  );
}

Not the prettiest but it gets the job done! I've also added Bulma so it's somewhat better looking than default. That's what the section and card classes are for:

Here's the CodeSandbox:

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. It's just an object.

Now with React, you don't have to differentiate between "is it a class?" or "should I use a functional component?"