nuzairb@gmail.com— press E to copy
FRONTEND ENGINEERING

React Hooks Changed How I Think About State

BY3 MIN READ

When React Hooks shipped I treated them as syntax sugar. Cleaner than class components, less boilerplate, same outcome. I rewrote a few components, liked the ergonomics, and moved on.

It took about a year of using them before I understood they were something more fundamental than that.

Key Takeaways

  • Hooks were not syntax sugar. Classes organise code around React's lifecycle stages; hooks let you organise it around your own concerns.
  • Because hooks are functions, they compose. Each layer stays simple while the composed behaviour gets complex — the same principle as function composition anywhere else.
  • After hooks, a long component file is a smell. If you cannot tell what a component does from its top-level structure in under a minute, the hooks were not extracted.

The class component mental model

In a class component, the unit of organisation is the lifecycle. You put data fetching in componentDidMount. You put cleanup in componentWillUnmount. You put derived state calculation in componentDidUpdate.

The logic for a single feature — say, a data table that fetches from an API, handles loading states, and refreshes when a filter changes — gets split across three or four lifecycle methods. The component file is organised around React's stages, not your feature.

This works. It scales badly. When a component has six features, each split across three lifecycle methods, the cognitive overhead of following any single feature through the file becomes significant.

What hooks changed

Hooks let you organise code by concern instead of by lifecycle stage.

function useTableData(filters: Filters) {
  const [data, setData] = useState<Row[]>([])
  const [loading, setLoading] = useState(false)

  useEffect(() => {
    setLoading(true)
    fetchData(filters).then(rows => {
      setData(rows)
      setLoading(false)
    })
  }, [filters])

  return { data, loading }
}

The fetch logic, the loading state, and the refetch trigger all live together in a custom hook. The component that uses it doesn't need to know any of that. It imports the hook, gets back what it needs.

The component file is now organised around what the component does for the user. The hooks are organised around what each piece of logic does for the component. Both layers are simpler separately than they were combined.

The composability consequence

Because hooks are just functions, they compose. useTableData can use useDebounce which uses useRef and useEffect. Each layer is simple; the composed behaviour is complex.

This is the same principle as function composition in general. Small, well-named functions that do one thing combine into larger behaviours without any single piece being difficult to understand.

I started thinking about state management differently as a result. Not "how do I manage state for this component" but "what is the shape of this concern, and what does a hook for it look like?"

What this changed about how I review code

Before hooks, a long component file was common and somewhat acceptable. There were only so many ways to organise class component code.

After hooks, a long component file is a smell. If a component's render function is doing significant computation, or if it's managing multiple distinct concerns, those concerns should be hooks. The component should read cleanly — mostly JSX, with a handful of hook calls at the top giving it what it needs.

If I'm reviewing a component and I can't understand what it does from its top-level structure in under a minute, the hooks haven't been extracted properly.

The thing no one mentioned

The shift from class components to hooks was positioned as an API change. It was actually a change in how you decompose problems.

Classes organised code around React's internals. Hooks let you organise code around your domain. There are still cases — a table of live prices ticking several times a second — where the right move is to leave React's model entirely. That's a larger change than the syntax suggests — and it still shapes how I think about every component I write.

WRITTEN BY

Design Engineer with 5+ years shipping production React and TypeScript interfaces across fintech, SaaS, and Web3. Writes about the seam between design and engineering.

Articles in the Same Series

FRONTEND ENGINEERING

The Case for Boring Tech in Client Projects

Feb 14, 2023
FRONTEND ENGINEERING

What Trading UIs Actually Need

Nov 22, 2022
FRONTEND ENGINEERING

What My First Real Client Taught Me About Frontend

Aug 14, 2020
FRONTEND ENGINEERING

Why I Stopped Reaching for Component Libraries First

Nov 13, 2019
FRONTEND ENGINEERING

The Gap Between Knowing JavaScript and Thinking in It

Apr 3, 2019
FRONTEND ENGINEERING

CSS Grid Finally Clicked — Here Is What Made It Make Sense

Jul 4, 2018
FRONTEND ENGINEERING

The Case for Boring Tech in Client Projects

Feb 14, 2023
FRONTEND ENGINEERING

What Trading UIs Actually Need

Nov 22, 2022
FRONTEND ENGINEERING

What My First Real Client Taught Me About Frontend

Aug 14, 2020
FRONTEND ENGINEERING

Why I Stopped Reaching for Component Libraries First

Nov 13, 2019
FRONTEND ENGINEERING

The Gap Between Knowing JavaScript and Thinking in It

Apr 3, 2019
FRONTEND ENGINEERING

CSS Grid Finally Clicked — Here Is What Made It Make Sense

Jul 4, 2018
FRONTEND ENGINEERING

The Case for Boring Tech in Client Projects

Feb 14, 2023
FRONTEND ENGINEERING

What Trading UIs Actually Need

Nov 22, 2022
FRONTEND ENGINEERING

What My First Real Client Taught Me About Frontend

Aug 14, 2020
FRONTEND ENGINEERING

Why I Stopped Reaching for Component Libraries First

Nov 13, 2019
FRONTEND ENGINEERING

The Gap Between Knowing JavaScript and Thinking in It

Apr 3, 2019
FRONTEND ENGINEERING

CSS Grid Finally Clicked — Here Is What Made It Make Sense

Jul 4, 2018
FRONTEND ENGINEERING

The Case for Boring Tech in Client Projects

Feb 14, 2023
FRONTEND ENGINEERING

What Trading UIs Actually Need

Nov 22, 2022
FRONTEND ENGINEERING

What My First Real Client Taught Me About Frontend

Aug 14, 2020
FRONTEND ENGINEERING

Why I Stopped Reaching for Component Libraries First

Nov 13, 2019
FRONTEND ENGINEERING

The Gap Between Knowing JavaScript and Thinking in It

Apr 3, 2019
FRONTEND ENGINEERING

CSS Grid Finally Clicked — Here Is What Made It Make Sense

Jul 4, 2018