reduxjs / redux-toolkit

The official, opinionated, batteries-included toolset for efficient Redux development
https://redux-toolkit.js.org
MIT License
10.7k stars 1.17k forks source link

useEffect not catching 'fulfilled' status change from RTK Query Mutation #3997

Closed TheBoyWhoLivedd closed 10 months ago

TheBoyWhoLivedd commented 10 months ago

Description

I am encountering an issue where a useEffect hook in my component is not responding to a 'fulfilled' status from a Redux Toolkit Query mutation. My useEffect hook is supposed to navigate to the home route when the logout mutation (useSendLogoutMutation) is fulfilled. The Redux store correctly updates the status to 'fulfilled', but useEffect seems to skip this status and does not trigger navigation.

Steps to Reproduce

  1. Dispatch useSendLogoutMutation to trigger a logout action.
  2. The logout action sends a POST request to the logout endpoint.
  3. The endpoint returns a 204 No Content status if no cookie is present.
  4. The RTK Query mutation updates the status to 'fulfilled' in the Redux store.
  5. The useEffect hook in DashHeader component is expected to catch this status change and navigate to the home route.

Expected Behavior

When the sendLogout mutation's status changes to 'fulfilled', the useEffect should trigger and call navigate("/").

Actual Behavior

The useEffect detects the 'pending' and 'uninitialized' status but skips the 'fulfilled' status. As a result, the expected navigation does not occur.

Attempts to Fix

Code Snippet

const [sendLogout, { isSuccess, status, isError, error }] = useSendLogoutMutation();

// useEffect hook in  component

  useEffect(() => {
    console.log("Effect status:", status);
    if (status === "fulfilled") {
      navigate("/");
    }
  }, [status, navigate]);

// Redux Toolkit Query mutation

sendLogout: builder.mutation({
  query: () => ({
    url: "/auth/logout",
    method: "POST",
  }),
  async onQueryStarted(arg, { dispatch, queryFulfilled }) {
    try {
      await queryFulfilled;
      dispatch(logOut());
      dispatch(apiSlice.util.resetApiState());
    } catch (err) {
      console.error(err);
    }
  },

}),

// Logout endpoint

const logout = (req, res) => {
  const cookies = req.cookies;
  if (!cookies?.jwt) return res.sendStatus(204); // No content
  res.clearCookie("jwt", { httpOnly: true, sameSite: "None", secure: true });
  res.json({ message: "Cookie cleared" });
};
image image

Environment

@reduxjs/toolkit": "^2.0.1" React version: [18.2..0] Browser: Chrome Operating System: Windows 11

phryneas commented 10 months ago

Can I suggest that instead you do

try {
  await sendLogout.unwrap()
  navigate("/");
} catch {}

in your click handler?

TheBoyWhoLivedd commented 10 months ago
  const sendLogoutHandler = async () => {
    try {
      await sendLogout({}).unwrap();
      navigate("/");
    } catch (error) {
      console.log(error);
    }
  };

This works and is my current workaround at the moment, but I'm still puzzled as to why the fulfilled status does not trigger the effect or appear in the console. This is the knowledge gap I'm seeking to fill. Any insights would be much appreciated.

Hillarykwok commented 2 months ago

Hello, can I ask if you figured out why isSuccess=false still? Because I’m facing the same issue while following a tutorial.