Alex's Notes

Why React Hooks (McGinnis)

Topic 1 of React Hooks: Tyler Mcginnis

What problems do hooks solve? To understand we need to review the history of the React API.

With ES6 JS introduced a class syntax, React leaned into it for the main API to create components before hooks came along.

Using the class syntax had trade offs:

The constructor had the issue of calling super so that you had access to this

You had to bind methods so that this would refer to the correct instance object all the time: this.method = this.method.bind(this)

These superficial things were solved by class fields.

But there were deeper issues. The lifecycle approach to updates resulted in duplicate logic. We had to handle didMount, didUpdate etc, often doing the same thing.

Worse, React was based on composing UI. Remember the core of react is the idea that view = fn(state) But there’s more to building an app than just the UI. Often you’ll need to share logic across components. How do you do that?

You would use higher order components. A component that took a component and wrapped it in logic. But this ended up crazy in practice, you’d end up with: withHover(withTheme(withAuth(withFunctionality(Component)))) Yuk.

And this would then render some horrible nested wrappers that make it hard to follow your actual app.

So React needed a better way to share non-visual logic, and organize logic in components other than lifecycles.

The answer was functions. Components would be plain functions. But then how to handle persistent state? How to share non-visual logic? And what to do about lifecycles?

State

We’ve done away with classes and instance objects, so how do we persist state? The answer is the useState method.

We call it inside a functional component passing some initial state, and it returns a tuple with a binding for that state, and a binding for a method to update it. Like this:

const [count, setcount] = React.useState(0)

Lifecycle Methods

In new React land, we take all we knew about lifecycle methods and throw it away. Lifecycle methods were not a solution in themselves, they were a step towards synchronization.

When we used lifecycle events, we were typically trying to synchronize something outside React land (an API request), with something inside it (component state).

Now we use the useEffect hook for this. This takes two arguments - a side effect to run, and an array of bindings to ‘watch’ and run the side-effect on change. Here’s an example (not from source):

const [count, setCount] = React.useState;

const updateBackground = () => {
  const body = document.querySelector('body');
  body.style.backgroundColor = `rgb(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255})`
}

React.useEffect(updateBackground, [count]);

Sharing non-visual logic

So the problem with React was coupling UI to component, so that it was hard to share non-visual logic across the app.

How does new React land solve this? Not via a built-in hook, but by creating custom hooks.

We’ll dig into this later.

Links to this note