I read an article on using react-query as a state manager and I am now trying to replace a context in my app with react-query (version 4).
Previously, I created a context with useContext() that stored a user account object for the logged-in user. I used react-query to fetch this data, and then useReducer() to modify the account object. However, I realized this is a mess and the relevant data is in react-query anyway, so I should get rid of the context and reducer and just use react-query directly (I am generating the user account object in the query that I make with react-query).
I generate the user account object in a custom hook:
function useUser(): UseQueryResult<User, Error> {
const query = getInitialUserUrl;
const platform = usePlatformContext();
return useQuery<User, Error>(
queryKeyUseUser,
async () => {
const data = await fetchAuth(query);
if (didQueryReturnData(data)) {
return new User(platform, data[0]);
}
return new User(platform);
},
{
refetchOnReconnect: 'always',
refetchInterval: false,
},
);
}
export default useUser;
Now I have a mutation where I verify the user's email address (old way using context):
const useMutationVerifyEmail = (): UseMutationResult<RpcResponseEmailVerify, Error, FormEmailVerifyInput> => {
const { userObject } = useUserContext();
return useMutation(
(data: FormEmailVerifyInput) => verifyEmail(userObject.id, data.validation_code),
},
);
};
I tried to replace the call to context with a direct call to useUser():
const useMutationVerifyEmail = (): UseMutationResult<RpcResponseEmailVerify, Error, FormEmailVerifyInput> => {
const { data: userObject } = useUser();
return useMutation(
(data: FormEmailVerifyInput) => verifyEmail(userObject.id, data.validation_code),
},
);
};
However, TypeScript complains that Object is possibly 'undefined' for userObject. I'm not sure why, because as far as I understand, useUser() always returns a User object.
How can I update my custom hook to return a User object so that I can use it instead of context?
UPDATE
I can wrap my useUser() hook in another hook:
function useUserObject() {
const { data: userObject } = useUser();
if (userObject instanceof User) {
return userObject;
}
throw new Error('Failed to get account info!');
}
And then I can do const userObject = useUserObject() to get the user account object... but is this really the optimal way? Do I need to create a custom hook for a custom hook just to use my user objects like I do with useContext()?
if(userObject)? Your hooks return type includes the possibility of an error.useMutationVerifyEmail, I can checkif (userObject instanceof User)to ensure the object is defined as you point out. But I'm trying to find a way to useuseUser()without having to check if the result is in fact aUserobject every time. I calluseUser()about 50 times in the app, and checking if the object is really there each time is a lot of boilerplate. I'm already catching errors in an error boundary so I'm hoping there's a way to refactor my code to avoid checking each time.