DEV Community

Cover image for React: understanding useReducer() & custom hooks
Manuel Artero Anguita 🟨
Manuel Artero Anguita 🟨

Posted on

1

React: understanding useReducer() & custom hooks

In React, useState() is the main brick 🧱 for building... pretty much everything.

Sure, we have contexts and memoization and references but the core are these guys.

const [item, setItem] = React.useState()
Enter fullscreen mode Exit fullscreen mode

The thing is, in real-world code we end up with several of these lego blocks working together.

Fake - not that fake - example out of context:

const [item, setItem] = React.useState<PlaylistItem | undefined>()
const [isPlaying, setIsPlaying] = React.useState(false);
const [itemFocus, setItemFocus] = React.useState<'plpause' | 'info-show' | 'info-hide'>('plpause');
const [time, setTime] = React.useState(0);
const [isShowingMoreInfo, setIsShowingMoreInfo] = React.useState(false);
Enter fullscreen mode Exit fullscreen mode

One tool in our toolboxes 🧰 for extracting state logic is useReducer().

In our - out of context - example we might want to refactor the state management. (Making easier to test this logic isolated or even share the logic with other components)

Let's say we define playlistState as the group of our state variables:
{ item + isPlaying + time + ... }

useReducer() collapses both the state and the update function:

const [ playlistState, dispatchPlaylistUpdate ] = useReducer(
  playlistReducer, 
  initialPlaylistState
)
Enter fullscreen mode Exit fullscreen mode

Now, all our update functions are replaced by the one-to-rule-them-all function (convention is to include "dispatch" in its naming):

- setItem(item)
+ dispatchPlaylistUpdate({ type: 'set-item', item })
Enter fullscreen mode Exit fullscreen mode
- setIsPlaying(isPlaying)
+ dispatchPlaylistUpdate({ type: 'is-playing', isPlaying })
Enter fullscreen mode Exit fullscreen mode
- setTime(time)
+ dispatchPlaylistUpdate({ type: 'set-time', time })
Enter fullscreen mode Exit fullscreen mode

...etc.

Side note 🗒️: At this point, I'd say it's easier to detect redundant states if we realize that calls to dispatchPlaylistUpdate({ }) are updating always the same state vars at the same time.


Now, I feel the urge to name the hook:

- const [ playlistState, dispatchPlaylistUpdate ] = useReducer(
-   playlistReducer, 
-   initialPlaylistState
- )
+ const { playlistState, dispatchPlaylistUpdate } = usePlaylist()
Enter fullscreen mode Exit fullscreen mode

And here we are, on the very slopes of Mount Doom 🌋, if we name each update call, using meaningful names...

- dispatchPlaylistUpdate({ type: 'set-item', item })
+ changeTrack(item)
Enter fullscreen mode Exit fullscreen mode
- dispatchPlaylistUpdate({ type: 'is-playing', isPlaying })
+ startTrack()
+ stopTrack()
Enter fullscreen mode Exit fullscreen mode
- dispatchPlaylistUpdate({ type: 'set-time', time })
+ updateTrackProgress(time)
Enter fullscreen mode Exit fullscreen mode

=>

- const { playlistState, dispatchPlaylistUpdate } = usePlaylist()
+ const { 
+  playlist, 
+  changeTrack, 
+  startTrack, 
+  stopTrack, 
+  updateTrackProgress
+ } = usePlaylist()
Enter fullscreen mode Exit fullscreen mode

We got a - IMO - more readable code.


In the end, these two codes are interchangeable, we've just refactored the thing:

const [item, setItem] = ...
const [isPlaying, setIsPlaying] = ...
const [time, setTime] = ...
Enter fullscreen mode Exit fullscreen mode

===

const { 
  playlist, 
  changeTrack, 
  startTrack, 
  stopTrack, 
  updateTrackProgress
} = usePlaylist()
Enter fullscreen mode Exit fullscreen mode

Note that I could have jumped right to the final refactor in this post, but I was trying to share my mental-model, my 'eureka' for understanding custom hooks.

--

Banner image by Storyset

Thanks for reading 💚.

SurveyJS custom survey software

Build Your Own Forms without Manual Coding

SurveyJS UI libraries let you build a JSON-based form management system that integrates with any backend, giving you full control over your data with no user limits. Includes support for custom question types, skip logic, an integrated CSS editor, PDF export, real-time analytics, and more.

Learn more

Top comments (0)

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay