FieldNotesFORRESTBLADE.COM ↗

2019-02-102 MIN[react][tutorial][hooks]

React Hooks Tutorial

Hooks are actually out now, 16.8, not an alpha anymore. I've been playing with them on a branch since the announcement last October and I'm writing down the beginner guide I wish I found on day one.

The whole idea is that a component can just be a function now. State used to be the reason you needed a class, and that's gone.

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      You clicked {count} times
    </button>
  );
}

That useState(0) line is the confusing part the first time. It returns an array with two things in it, the current value and a function that updates the value, and the square brackets are just destructuring so you can name them whatever you want. The 0 is the starting value. When you call setCount, React re-runs your function with the new value and the screen updates. That's the entire trick. No this.state, no this.setState, no constructor, no bind.

For comparison, the same thing as a class is a constructor, a state object, a bound handler or an arrow class property, and about three chances to mess up this. I've written that class fifty times and I'm not going to miss it.

The second one you need is useEffect. Anything you used to do in componentDidMount or componentDidUpdate, like fetching data or touching the document, goes in here.

import React, { useState, useEffect } from 'react';

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

  useEffect(() => {
    document.title = 'Clicked ' + count + ' times';
  }, [count]);

  return (
    <button onClick={() => setCount(count + 1)}>
      You clicked {count} times
    </button>
  );
}

The array at the end is the dependency list. It means only run this effect when count changed. Leave the array empty and it runs once when the component mounts, which is where your fetch calls go. Leave the array off entirely and it runs after every single render, which is bad lol.

Two rules. Only call hooks at the top level of your function, never inside an if or a loop, because React tracks them by the order they run in. And only call them from React function components or your own custom hooks. There's an eslint plugin, eslint-plugin-react-hooks, that yells at you when you break either rule.

Class components still work fine and the React team said they're not removing them. New stuff in functions with hooks, old stuff stays where it is until you have a reason to touch it. That's what we're doing at work and it's been fine.