I am using Redux-Toolkit (RTK) Query to log a user into my React application, and when the user clicks the "logout" button, it should redirect to the home page, "/"
. However, when I click "logout" button, the page doesn't redirect to the home page.
In my Layout.jsx, I use useEffect
hook to check whether the mutation succeeded
const navigate = useNavigate();
const [sendLogout, { isLoading, isSuccess, isError, error }] =
useSendLogoutMutation();
useEffect(() => {
if (isSuccess) {
console.log("success");
navigate("/");
}
}, [isSuccess, navigate]);
In my authApiSlice.js, when I comment out dispatch(apiSlice.util.resetApiState());
, the isSuccess
value in the code above works, however, if I add the code dispatch(apiSlice.util.resetApiState());
, it doesn't work again.
import { apiSlice } from "../../app/api/apiSlice";
import { logOut } from "./authSlice";
export const authApiSlice = apiSlice.injectEndpoints({
endpoints: (builder) => ({
login: builder.mutation({
query: (credentials) => ({
url: "/auth",
method: "POST",
body: { ...credentials },
}),
}),
sendLogout: builder.mutation({
query: () => ({
url: "/auth/logout",
method: "POST",
}),
async onQueryStarted(arg, { dispatch, queryFulfilled }) {
try {
const { data } = await queryFulfilled;
// console.log(data);
dispatch(logOut());
dispatch(apiSlice.util.resetApiState());
} catch (err) {
console.log(err);
}
},
}),
refresh: builder.mutation({
query: () => ({
url: "/auth/refresh",
method: "GET",
}),
}),
}),
});
export const {
useLoginMutation,
useSendLogoutMutation,
useRefreshMutation
} = authApiSlice;
I don't understand what I did wrong.
I don't think you did anything overtly wrong, per se, but resetting the API slice state during a mutation request processing probably isn't the best thing to do since this appears to clear in-flight requests and their associated metadata.
That said, you don't need to wait for the mutation endpoint to complete and trigger the component using the useSendLogoutMutation
to rerender so the mutation results are accessible, the sendLogout
trigger function returns a Promise that be used to run additional logic after a successful mutation call. I suspect this could work for you here.
See useMutation signature:
type UseMutation = ( options?: UseMutationStateOptions ) => [UseMutationTrigger, UseMutationResult | SelectedUseMutationResult]
type UseMutationTrigger<T> = (arg: any) => Promise< { data: T } | { error: BaseQueryError | SerializedError } > & { requestId: string // A string generated by RTK Query abort: () => void // A method to cancel the mutation promise unwrap: () => Promise<T> // A method to unwrap the mutation call and provide the raw response/error reset: () => void // A method to manually unsubscribe from the mutation call and reset the result to the uninitialized state }
Invoke the sendLogout
trigger function and await
its unwrapped result.
Example:
const navigate = useNavigate();
const [
sendLogout,
{ isLoading, isError, error }
] = useSendLogoutMutation();
...
const logoutHandler = async () => {
try {
await sendLogout().unwrap(); // <-- trigger mutation and await success
// Success, redirect to home
navigate("/", { replace: true });
} catch(error) {
// handle/ignore any thrown errors or Promise rejections
}
};
...
If there's still an issue with resetting the API slice from within the sendLogout
endpoint then my suggestion would be to reset it after the mutation succeeds. Similar to above.
...
sendLogout: builder.mutation({
query: () => ({
url: "/auth/logout",
method: "POST",
}),
async onQueryStarted(arg, { dispatch, queryFulfilled }) {
try {
const { data } = await queryFulfilled;
dispatch(logOut());
} catch (err) {
console.log(err);
}
},
}),
...
const dispatch = useDispatch();
const navigate = useNavigate();
const [
sendLogout,
{ isLoading, isError, error }
] = useSendLogoutMutation();
...
const logoutHandler = async () => {
try {
await sendLogout().unwrap();
// Success, reset API state and redirect to home
dispatch(apiSlice.util.resetApiState()); // <-- reset after success
navigate("/", { replace: true });
} catch(error) {
// handle/ignore any thrown errors or Promise rejections
}
};
...