Using Generics with Components 11 exercises
Problem

Build a useMutation hook

Consider this complex useMutation hook that allows us to pass any mutation into its opts, then returns a mutate function.


export const useMutation = (opts: UseMutationOptions): UseMutationReturn => {
const [isLoading, setIsLoading] = useState(false);
return {
mutate: async

Loading exercise

Transcript

00:00 In this exercise, we have quite a complex hook here. It's called useMutation. What useMutation does is it takes in a mutation in its options, and then it has a return which has a mutate in it. What this does is it means we can basically pass in any mutation in here.

00:18 Let's say we've got a createUser here. This createUser is actually coming from a fake external lib that I've just created for the sake of this. We look inside createUser, we can see that it takes in user, name, e-mail, and the second thing which is options here, so throw an error or not. It returns a promise with ID, name, and e-mail in it.

00:37 It's returning our user that we've just created with the name and e-mail. Of course, this is all mocked up. It doesn't really do anything, but this is basically just to get the types here so that we can infer them in our useMutation hook. What's going on inside the hook is you don't need to worry about this too much.

00:55 We have an isLoading boolean and setIsLoading boolean, and inside this mutate, what we're doing is we're basically setting isLoading true. We're running the mutation and then just returning the results. If we have an error there, then we just throw the error. This is mocking something like saving it in a state value or something like this.

01:15 But finally, we set isLoading false. Then we return mutate and isLoading inside here as we've got it set up in our useMutation return. But what we want to do is we want to say basically, okay, mutation.mutate, we should be able to pass in the right stuff. We shouldn't be able to pass in the wrong stuff.

01:34 So here e-mail is missing, and here we can't pass in extra stuff to the mutation.mutate. Currently, we can just pass in anything inside here actually. It's actually inferred as args any and returns a promise any. So it should be this. This is the full type that mutation.mutate should be.

01:54 And mutation.isLoading is working fine, but this is very much not. Currently, mutation.mutate is just this type of mutation. How many times can I say the word mutation without this being like an X-Men reference? So we obviously need to make useMutation into a generic function.

02:12 And we need to get rid of these anys inside here and capture them in some other way. So your job is to try to find a way that we can take all of this stuff here and use the right constraints and use the right sort of flow and the right type arguments,

02:30 the right expression for those type arguments to get this all working. Good luck.