Extract Generic React Hook Code into Custom React Hooks

Kent C. Dodds
InstructorKent C. Dodds

Share this video with your friends

Send Tweet

Because hooks code is regular JavaScript, extracting it to its own function is trivial and enables code sharing in a really nice way. It also allows us to encapsulate and separate concerns really cleanly. Custom hooks also compose really nicely together to build more complex hooks out of more primitive ones. Let's do this by creating a useSetState and useSafeSetState custom hook.

If you would like a more comprehensive useSetState hook, give use-legacy-state a try.

Instructor: [00:00] One of the cool things about React hooks is that it's really just JavaScript. This is just some JavaScript that we're running right here. This is some JavaScript. We're just calling a couple functions, and we can extract this into our own custom functions.

[00:12] I'm going to take this logic right here, and I'm going to make a useSetState custom hook. We'll say useSetState, and then we'll just move this right up here. Then we can return state and setState. Then we can actually pull in our state and setState from useSetState.

[00:33] That was just a pure refactor, not really actually changing any behavior at all, just moving code around. Now, we want to make this actually generically useful. Having this loading fetching data and error state in here as the initialize state doesn't really make sense in the context of other components.

[00:50] I'm going to actually take this out, and we'll call this initialState. Then we'll put in initialState here. Then we'll pass that initial state to our call to useSetState. That's just another refactor, just moving things around.

[01:05] Now, we can use this useSetState function anywhere, and we can get an experience in refactoring other components in a way that's similar to the way setState works in React. Again, we're not supporting the updater function API from setState or the callback as the second argument to setState.

[01:23] This is covering our use cases here, and we could add support for those later, or we could actually use the NPM module, use-legacy-set-state, which is basically this.

[01:33] The next thing that I want to do is, this also could be usefully generic. I'm going to make a new hook here that's called useSafeSetState. Here, it's going to take some initial state as well. What we're going to do is I'm actually going to reuse this useSetState in here.

[01:50] I'm going to get my state and setState. We'll call useSetState with initial state. Then I'm going to take this mounted ref all the way down to the safeSetState down here. We'll just put it right there. From here, we'll return state and safeSetState.

[02:09] Then we can actually just use safeSetState right here. This can be safeSetState. Cool. Now, we'll just update that setState call there to use safeSetState instead, which will work just fine.

[02:23] Now, we've been able to extract some generic code from our query component into these little custom hooks that encapsulate some specific use cases, and are even composed together to form a really nice, cohesive useSafeSetState hook.

[02:38] Really, the way that we did this was we just moved some code around, made some functions, and then called those functions instead of the React hooks directly in our query. Now, if we save this, and go here, just to make sure that things are working, it is still working.

Rob Eberhardt
Rob Eberhardt
~ a year ago

I'm receiving a "Hooks can only be called inside the body of a function component." warning after making the changes in this video.

It looks like the treatment of useSafeSetState inside the useEffect differs in this Video and the Git repo.

Kent C. Dodds
Kent C. Doddsinstructor
~ a year ago

I'm not sure what you're looking at. Here's what I see when I click the GitHub button above and navigate to this file: https://github.com/kentcdodds/react-github-profile/blob/1bbf5d9ff69197ac4f03a4612348bc2b5247b957/src/screens/user/components/query.js#L13-L24