Course: Section

Get Started with Modern React: Learn by Doing

Episode: Title

S03・V09: Component State

Date Created: July 17th, 2019
Last Updated: 27 days ago

Objectives
  1. What component state is and the React “hooks” feature for enabling it.
  2. How to use the `useState` hook.
Watch Video
Duration: 4m 54s

State

As a next step for our tic-tac-toe game, we want the Square component to “remember” that it was clicked, and fill it with an X or an O mark. If a Square has not yet been clicked, it is empty, and it should have a value of null

To “remember” things, components use state. Unlike props, which is data that comes from a parent component, state is data that originates from the component itself, which is why it is also referred to as “local state”.

Hooks, not Classes

Until React 16.8 which was released in February 2019, the only way for a React component to remember state was to set it up as a “class” component. Now, JavaScript classes have some peculiarities and complexities that make them hard for beginners to use. Fortunately, with React 16.8, a new feature called “hooks” was introduced, enabling React function components, like the ones we have been using up to now, to remember state.

useState Hook

React Hooks are very convenient. The React hook that we need to remember state with is called the useState hook.

The useState hook is a named import in React:

import React, { useState } from 'react';

Let’s use this hook, and then explain how it works. We will have the Square component remember the state of the value inside itself. That is, each Square will remember if it has an X, an O or a null value.

At the top of the Square function component, add the following code:

const Square = props => {
  const [value, setValue] = useState(null);
  return (
    <button
      className="square"
      onClick={() => alert('click')}
    >
      {props.value}
    </button>
  );
};

The useState hook is a function that takes the initial value of the state variable it should remember. In this example, the initial value is null. The useState function returns an array that contains two elements:

  • The first array element gets the current value of the state variable it is remembering. Using array destructuring, the state variable in this case is called value.
  • The second element of the array returned by useState is a function that enables you to set the value of the state variable. Again using array destructuring, the function is called setValue, and its input is what you want to set the state variable value to be.

The array destructuring notation is quite elegant. The first element is the state variable “getter”, and the second element is the state variable “setter”.

Implementing the Square’s Click Handler

Now, we’ll change the Square’s return expression to display the current state variable’s value when clicked. First, we will replace the value obtained via props from the parent Board component, to be the state variable value remembered by the useState hook. Now that we are no longer using the props object, we can remove it from the function input.

const Square = props => {  const [value, setValue] = useState(null);

  return (
    <button
      className="square"
      onClick={() => alert('click')}
    >
      {props.value}    </button>
  );
};

Next, we will update the state variable value when the user clicks on the Square, and for the time being, we will set it to X. We can do this by updating the button onClick handler to make use of the setter function. This is the second element in the array returned by our useState hook.

const Square = props => {
  const [value, setValue] = useState(null);

  return (
    <button
      className="square"
      onClick={() => setValue('X')}    >
      {props.value}
    </button>
  );
};

By calling setValue('X') from the onClick handler, we are telling React to re-render the Square whenever the button is clicked.

After the user clicks on a Square, the Square’s state value will be X so we’ll see the “X“ on the game board for that Square. Let’s click on the Square with index 0. Click on the Square with index 6. Then, click on the Square with index 8.

We now have successfully implemented setting the Squares’ values.

Code Snapshot

src/index.js
import React, { useState } from 'react';
import ReactDOM from 'react-dom';

import './index.css';

const Square = () => {
  const [value, setValue] = useState(null);

  return (
    <button
      className="square"
      onClick={() => setValue('X')}
    >
      {value}
    </button>
  );
};

const Board = () => {
  const renderSquare = i => {
    return (
      <Square value={i} />
    );
  };

  return (
    <div style={{
      backgroundColor: 'skyblue',
      margin: 40,
      padding: 20,
    }}>
      Board
      <div className="board-row">
        {renderSquare(0)}
        {renderSquare(1)}
        {renderSquare(2)}
      </div>
      <div className="board-row">
        {renderSquare(3)}
        {renderSquare(4)}
        {renderSquare(5)}
      </div>
      <div className="board-row">
        {renderSquare(6)}
        {renderSquare(7)}
        {renderSquare(8)}
      </div>
    </div>
  );
};

const Game = () => {
  return (
    <div className="game">
      Game
      <Board />
    </div>
  );
};

ReactDOM.render(
  <Game />,
  document.getElementById('root')
);

Summary

We introduced component state, and we made use of the useState hook to implement it.

Next Up…

In the next video, we will explain what “lifting state up” means and why it is important.