Kent C. Dodds - Advanced Hooks

Kent C. Dodds - Advanced Hooks

Published on Wednesday 1st April, 2020.

Here we go again! Round 4! This time we're diving into Advanced Hooks.

As the whole world seems to have moved onto Zoom my connection seems to be getting worse and worse. So, I struggled with a lot of lag today. I don't know if that was because everyone in my area was online or just the way it happened to fall.

These workshops are coming thick and fast. I know I'll revisit these posts as I revisit the learning over the coming months. So, see this as a work in progress of my learning and thinking on these topics.

useReducer: simple Counter

This is a deliberately simple example to allow us to focus on the API.

Why not just use useState with an object when you want to deal with multiple states?

The reducer hook has a more intuitive way to deal with more complex state - it basically has a better API.

Here's an example of using useReducer to manage the value of a name in an input.

function nameReducer(previousName, action) {
return action
const initialNameValue = 'Joe'
function NameInput() {
const [name, setName] = React.useReducer(nameReducer, initialNameValue)
const handleChange = event => setName(
return (
Name: <input defaultValue={name} onChange={handleChange} />
<div>You typed: {name}</div>

It was good to get into the workings of this API and see the things built up from a useState basic state.

State needs to be treated immutable.

As always, Kent has blog posts to answer most questions that come his way.

How to use React Context effectively

Implementing a simple state machine in JS

Immer - to deal with immutable state

useCallback: custom hooks

The first exercise here was to create a custom hook to generalize some async behaviour.

For this to work, there was an issue that passing in the dependency array can't be linted or type checked. We use useCallback to memoize a callback function so that we can depend on the same function being called for the same values. This stops infinite rerendering when we pass the function itself as a dependency.

useMemo and useCallback

useContext: simple Counter

Sharing state without having to prop drill - this is noisy and creates some issues with maintainance.

You mightn't need to use context as soon as you expect. Michael Jackson suggests composition is a useful pattern.

Interesting to create a CountProvider component rather than having the state managed in the app. Then the state can be handled away from the component logic.

How to use context effectively

How to optimize your context value

Kent continues the blogpost provision :)

Application State Management

State Co-location

Having separate providers allows us to modularise our state and not have unexpected breaks. It makes it easier to reason about and makes things more performant. react-table library

useLayoutEffect: auto-growing textarea

There are two ways to tell React to run side-effects after it renders:

  1. useEffect
  2. useLayoutEffect

The difference about these is subtle (they have the exact same API), but significant. 99% of the time useEffect is what you want, but sometimes useLayoutEffect can improve your user experience.

To learn about the difference, read useEffect vs useLayoutEffect

Basically, for visual effects we use useLayoutEffect. Most effects are not visibly observable.

React hooks pitfalls

and in talk form

useImperativeHandle: scroll to top/bottom

I hadn't seen this hook before and it seems pretty interesting. This allows us to pass back imperative handlers if the user passes a ref to the component. This was achieved in class components with creating a reference inside the instance of the component, but this isn't possible in functional components.

Now, we create a ref and forward it to the component. The component then uses that ref to pass back handler function that can be used to imperatively direct the component.

useDebugValue: useMedia

We can add debug messages to our hooks to be able to see what is being referenced. There is a formatCountDebugValue that can be used to give a better output.