DEV Community

craig martin
craig martin

Posted on • Edited on

Hooks for those who know React

React Hooks are not a new concept: they are "just react"

Hooks are not a new concept in React - they are a re-implementation (a new API) for state and side effects in React that better aligns with two existing concepts in react: the concept of Components as the primitive model for UIs, and of these components being declarative.

Declarative Code and Component UI Primitives are two essential concepts of React

Let's look at the concept of Components as the UI Primitives first. Before hooks, Components are a mental idea that don't map directly to either of the two existing implementations: the class-based or function-based. While the mental model was right, the implementation was forced. And so you’d have to sometimes switch between them.

Before Hooks, switching between component implementations was common

What’s going on is there is a missing primitive for components: a single Component implementation which is like stateful functions with effects - and that is what hooks enable.

Before Hooks, there is a missing primitive for components

Before looking at how Hooks solves for this, let’s look at the other concept hooks are better aligned with: Using declarative code to make components easier to reason about.

React components have always allowed declarative code to be mapped to an imperative DOM. In the case of functional components, this declarative approach included not just the render, but the whole component (b/c the whole component was just a render): a mapping of data to an object describing the UI. React would take this object and surgically (imperatively) update the DOM.

However, if a component needed local state or side-effects - it had to be implemented as a class components. And while the render function was still declarative, the class instance itself (where the state lived and side-effects were managed) was mutable. State and side-effects were tied to a mutating instance, which made them harder to reason about.

The react team wanted the single missing component primitive to itself be declarative (as functional components were), even when it included state and side-effects.

Hooks provide for this missing component primitive. They allow components to be truly declarative even if they contain state and side-effects. They are a re-conception and re-implemenation of state and side-effects in React - an implementation instead of in class components, is in functional components making use of "hooks".

Hooks make components declarative even if they contain state or side-effects

"Ok, Yeah, cool, whatever.. So what are hooks?"

Hooks are functions used with functional components that let you "hook into" React state and perform side-effects (as previously done with lifecycle hooks).

React provides built-in Hooks, and these can even be used to build more advanced custom hooks.

By convention hook functions are prefixed with “use”.

While hooks are “just functions”, they are not your father’s functions... They do not behave like normal functions. We'll come back to that.

Hooks do not behave like normal functions

The useState hook for managing local state

Rather than the state living on a mutable this instance of the component (this.state and this.setState), state is declaratively retrieved from the useState hook.

State is now retrieved and set declaratively without mutating the structure of the component (ie as the class instance would be).

Rather than the state living on a mutable `this` instance of the component, state is declaratively retrieved from the hook

The highlighted line shows the useState hook. The value passed is the initial value. The hook returns an array for two items, state and a setter for that state, and we destructure them to variables count and setCount.

The useEffect hook for managing side-effects

Rather than side-effects being aligned with the component's mutation (componentDidMount, componentDidUpdate, componentWillUnmount), they are now declaratively aligned with state using the useEffect hook.

useEffect orients the side effect (and it’s clean-up) with the state, rather than component’s mutation.

Rather than side-effects being aligned with the component's mutation, they are declaratively aligned with state using the hook

The highlighted line shows the useEffect hook. We pass in a function that performs some side-effect, and the state that that effect is coupled with. Whenever that state changes, the effect function is run.

"But hold on.. WTF.. wouldn't these hooks be reset every render?"

"The hooks are created inside the functional component which are called for every render. Looking back up at the useState example, wouldn't const [count, setCount] = useState(0); be called every render and keep reseting the count to the initial value of 0?"

It would seem that way, if useState was a typical function - but it's not. Hooks are impure* functions - but that impurity is an implementation detail in React that is abstracted away from userland code.
*They are impure as a consequence of JS being the host language, which does not support Algebraic Effects.

Hooks are not typical functions

An example using hooks

Here is a contrived example using the useState and useEffect hooks, vs using class components and lifecycle methods.

Example of functional components with hooks, vs class components

Here is live code of the hooks version (on the left): https://codesandbox.io/s/greeting-hooks-2uwdg

Here is live code of the class component version (on the right):
https://codesandbox.io/s/greeting-classes-7bmql

Notice how in the hook version, state and effects are kept together.

Example showing the code groupings of functional components with hooks, vs class components

A second example using hooks

Lets look at a second example of using hooks. Here are two versions of a contrived component which lets you search for a user, and edit their name.

Here is the hooks version: https://codesandbox.io/s/react-hooks-are-a-better-mental-model-f9kql

Here is the class version: https://codesandbox.io/s/react-classes-are-the-wrong-mental-model-n9zbs

Notice how, again, the state and effects are kept together with hooks - but more-so this time that a bug is avoided which is in the class component version. ("Save" a user, and while it is saving change the users name. The confirmation message will confirm the wrong name - the newly updated one rather than the one which was saved. This is because by the time the save side-effect finishes, the state is mutated. With hooks, state is functionally-scoped and closed-over, and each render introduces new immutable state.)

Custom Hooks add the missing primitive for state/effect sharing.

Now that we've got a grasp on hooks - how functional components using hooks are a new UI primitive which make state and side-effects easier to reasonable through a declarative API - there is one more important note: beyond just co-locating the state and side-effects, these can be abstracted out into a custom re-useable hook. Hooks represent a primitive for state/effect sharing, as Components are a primitive for UI sharing. Building custom Hooks allow for extracting component logic into reusable functions.

Looking back at our first example. We can build a custom useWidth hook that extracts the width state and effect. Then that hook can be re-used by any component!

Here is live code showing the above: https://codesandbox.io/s/greeting-hooks-as-a-primative-xb0o0

At first glance, it may look like this code-sharing could have been achieved by making a Width component. But that gets at the heart of it: we don't want a re-useable UI primitive, we want a re-useable state/effect primitive. If it were a UI primitive, the state and effects would be tied to a UI representation - we just want the data, so it can be presented however different components decide.

What other built-in Hooks are there?

Basic Hooks

  • useState
  • useEffect
  • useContext

Additional Hooks

  • useReducer
  • useCallback
  • useMemo
  • useRef
  • useImperativeHandle
  • useLayoutEffect
  • useDebugValue

More resources

Introducing Hooks (reactjs.org)
Making Sense of React Hooks (medium.com)
A Complete Guide to useEffect (overreacted.io)
Thinking in React Hooks (wattenberger.com)

Individual Photos of Class vs Hooks code with and without Highlighting

Classes: https://thepracticaldev.s3.amazonaws.com/i/9t0sa5bfzos9nh8yfumy.png
Classes Highlighted: https://thepracticaldev.s3.amazonaws.com/i/ah9b8plpz32jejub7nfl.png

Hooks: https://thepracticaldev.s3.amazonaws.com/i/gupc51cvr005gnkuzriu.png
Hooks Highlighted: https://thepracticaldev.s3.amazonaws.com/i/p0tr7pzokmlovbm1v3bw.png

Together:
https://thepracticaldev.s3.amazonaws.com/i/8kt6btrmwqpa1mnffzi9.png
Together Highlighted:
https://thepracticaldev.s3.amazonaws.com/i/bqk4xi68eidx7jmwq6ca.png

Top comments (1)

Collapse
 
xiaokedada profile image
小可嗒嗒

Why a class component instance is not declarative?