---
description: >-
  Learn how to use the useState and useEffect hooks to create dynamic
  interactions in React
---

# React state & effects

React is designed to build dynamic apps with lots of interaction. A common difficulty with apps like this is keeping the DOM up-to-date as the user interacts. React has two concepts to help keep this manageable: "state" and "effects".

### React state

State is data that changes while your application is running. This might be in response to user actions, or after a `fetch` request finishes.

In React all stateful values are stored in JS as special variables. We can render our UI based on these variables—when they change React will automatically re-run the component function and update the DOM to reflect the new state value.

#### Using state

Imagine we have a counter component. When the button is clicked we want the count to go up one:

```jsx
function Counter(props) {
  const count = 0;
  return <button>Count is {count}</button>;
}
```

We need some way to make our `Counter` function run again if this value changes.

The `React.useState` method can be used to create a "stateful" value. It takes the initial state value as an argument, and returns an array. This array contains two things: the state value, and a function that lets you _update_ the state value.

```jsx
function Counter(props) {
  const stateArray = React.useState(0);
  const count = stateArray[0];
  const setCount = stateArray[1];
  return <button>Count is {count}</button>;
}
```

It's common to use array destructuring to simplify this:

```jsx
function Counter(props) {
  const [count, setCount] = React.useState(0);
  return <button>Count is {count}</button>;
}
```

The `setCount` function lets us update our state value and tells React to re-run this component. E.g. if we called `setCount(10)` React will call our `Counter` component function again, but this time the `count` variable would be `10` instead of `0`.

This is how React keeps your UI in sync with the state.

### Event listeners

We have a function that will let us update the state, but how do we attach event listeners to our DOM nodes?

```jsx
function Counter(props) {
  const [count, setCount] = React.useState(0);
  function increment() {
    setCount(count + 1);
  }`
  return <button onClick={increment}>Count is {count}</button>;
}
```

You can pass event listener functions in JSX like any other property. They are always formatted as "on" followed by the camelCased event name. So "onClick", "onKeyDown", "onChange" etc.

In this example we are passing a function that calls `setCount` with our new value of `count`.

![counter-example](https://user-images.githubusercontent.com/9408641/57850062-e9281100-77d4-11e9-81cc-befd42f1faf7.gif)

### Challenge 1

Time to add some state! Open up `challenge-1.html` in your editor. You should see the `Counter` component we just created. This is an example; you can delete it if you want.

Create a new component called `Toggle`. It should render a button that toggles a boolean state value when clicked. It should also render a div containing its children, but only when the boolean state value is true.

Example usage:

```jsx
function App() {
  return <Toggle>This text is hidden until the button is clicked</Toggle>;
}
```

![toggle-example](https://user-images.githubusercontent.com/9408641/57849940-98b0b380-77d4-11e9-86ef-315861f60489.gif)

### Side effects

React is designed to make it easy to keep your application in sync with your data/state. Component functions render DOM elements and keep them in sync with any state values.

But most apps need more than just a UI—there are also things like fetching data from an API, timers/intervals, global event listeners etc. These are known as "side effects"—they can't be represented with JSX.

We need a way to ensure our effects reflect changes in state just like our UI does.

#### Using effects

React provides another "hook" like `useState()` for running side-effects _after_ your component renders. It's called `useEffect()`. It takes a function as an argument, which will be run after every render (by default).

Let's say we want our counter component to also update the page title (so the count shows in the browser tab). There's no way to represent this update using the JSX our component returns. Instead we can use an effect:

```jsx
function Counter(props) {
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    document.title = `Count: ${count}`;
  });

  return <button onClick={() => setCount(count + 1)}>Count is {count}</button>;
}
```

![effect-example](https://user-images.githubusercontent.com/9408641/57864430-c9ecac00-77f3-11e9-8811-1242688c3e7d.gif)

React will run the arrow function we passed to `useEffect()` every time this component renders. Since calling `setCount` will trigger a re-render (as the state is updated) the page title will stay in sync with our state as the button is clicked.

#### Skipping effects

By default all the effects in a component will re-run after **every** render of that component. This ensures the effect always has the correct state values.

If your effect does something expensive/slow like fetching from an API (or sorting a massive array etc) then this could be a problem.

`useEffect()` takes a second argument to optimise when it re-runs: an array of _dependencies_ for the effect. Any variable used inside your effect function should go into this array:

```jsx
function Counter(props) {
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    document.title = `Count: ${count}`;
  }, [count]);

  return <button onClick={() => setCount(count + 1)}>Count is {count}</button>;
}
```

Now our effect will only re-run if the value of `count` has changed.

#### Running effects once

Sometimes your effect will not be dependent on _any_ props or state, and you only want it to run once (after the component renders the first time). In this case you can pass an empty array as the second argument to `useEffect()`, to signify that the effect has no dependencies and never needs to be re-run.

For example if we wanted our counter to increment when the "up" arrow key is pressed:

```jsx
function Counter(props) {
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    function handleKeyDown(event) {
      if (event.key === "ArrowUp") {
        setCount((prevCount) => prevCount + 1);
      }
    }
    window.addEventListener("keydown", handleKeyDown);
  }, []);

  return <div>Count is {count}</div>;
}
```

We add an event listener to the `window`, and pass an empty array to `useEffect()`. This will keep us from adding new event listeners every time `count` updates and triggers a re-render.

#### Cleaning up effects

Some effects need to be "cleaned up" if the component is removed from the page. For example timers need to be cancelled and global event listeners need to be removed. Otherwise you'd have a bunch of code running in the background trying to update a component that doesn't exist anymore.

If you return a function from your effect React will save it and call it if the component is removed from the page. React will _also_ run it to clean up when a component re-renders (before the effects run again).

Let's clean up after our effect example from above:

```jsx
function Counter(props) {
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    function handleKeyDown(event) {
      if (event.key === "ArrowUp") {
        setCount((prevCount) => prevCount + 1);
      }
    }
    // run handler function when keydowns happen
    window.addEventListener("keydown", handleKeyDown);
    // create fn that removes event listener
    function cleanup() {
      window.removeEventListener("keydown", handleKeyDown);
    }
    // react will run `cleanup` whenever it needs to remove this effect
    return cleanup;
  }, []);

  return <div>Count is {count}</div>;
}
```

The `cleanup` function we return will be called if the component unmounts (is removed from the page). That will ensure we don't keep running an unnecessary event listener and trying to update state that doesn't exist anymore.

### Challenge 2

We're going to enhance our `Toggle` component from Part 3. You can either keep working in the same file or open up `challenge-2.html` to start fresh.

1. Edit the Toggle component so that the page title (in the tab) shows whether the toggle is on or off.
2. Then create a new component called `MousePosition`. It should keep track of where the mouse is in the window and render the mouse x and y positions.
3.  Put `MousePosition` inside your `Toggle` so you can show and hide it. This is how your final `App` should look:

    ```jsx
    function App() {
      return (
        <Toggle>
          <MousePosition />
        </Toggle>
      );
    }
    ```

![effect-example](https://user-images.githubusercontent.com/9408641/58380308-758dbd00-7fa7-11e9-8e93-cdc945530d55.gif)
