skip to Main Content

in a React App which I have to use redux, I’m trying to change a button link "Sign in" into " Log Out " when a token is in Cookies.
but the state "isLogged" doesn’t update , but it update only when I refresh the page manually.

How can I do that automatically ?

Here is the code for that:

const token = Cookies.get("token");
const [isLogged, setIsLogged] = useState(false);

useEffect(() => {
  if (token) {
    setIsLogged(true);
  }
}, [token]);

const handleLogout = () => {
  Cookies.remove("token");
  setIsLogged(false);
  console.log("logout");
};

Here is the code for the token which I get correctly in the signIn page:

// call api
const [getToken, { isLoading, isError }] = useGetTokenMutation();

// handle submit
const handleSubmit = (e) => {
  e.preventDefault();
  getToken({ email, password })
    .unwrap() // Récupère le résultat du token de la promesse
    .then((data) => {
      const token = data.body.token;
      Cookies.set("token", token, { expires: 1 });
      navigate("/users");
      setErrorMessage("");
    })
    .catch((error) => {
      setShakingAnimation(true);
      setTimeout(() => {
        setShakingAnimation(false);
      }, 500);
      setErrorMessage(error.data.message);
    });
};

And here is the API slice from redux:

export const apiSlice = createApi({
  reducerPath: "api",
  baseQuery: fetchBaseQuery({
    baseUrl: "http://localhost:3001/api/v1/",
  }),
  tagTypes: ["User"],
  endpoints: (builder) => ({
    getToken: builder.mutation({
      query: (user) => ({
        url: "user/login",
        method: "POST",
        body: user,
      }),
      invalidatesTags: ["User"],
    }),
  }),
});

export const { useGetTokenMutation } = apiSlice;

Link Github project

Thanks for your help.

2

Answers


  1. Chosen as BEST ANSWER

    I have a new problem concerning the refresh:

    So now after the successful sign-in, when I'm refreshing the page, I'm logged out but I can still see the token on the Chrome devtool. But the state token from redux is empty ( whereas it has the token when I sign in ) here is the authSlice :

    const authSlice = createSlice({
      name: "auth",
      initialState: {
        isLoggedIn: "",
      },
      reducers: {
        setLoggedIn: (state, action) => {
          state.isLoggedIn = action.payload;
        },
        setLoggedOut: (state) => {
          state.isLoggedIn = "";
        },
      },
    });
    

    here is the submit button :

      const handleSubmit = (e) => {
        e.preventDefault();
        getToken({ email, password })
          .unwrap() // Récupère le résultat du token de la promesse
          .then((data) => {
            const token = data.body.token;
            Cookies.set("token", token, { expires: 1 });
            setErrorMessage("");
            dispatch(setLoggedIn(token));
            navigate("/users");
          })
          .catch((error) => {
            setShakingAnimation(true);
            setTimeout(() => {
              setShakingAnimation(false);
            }, 500);
            setErrorMessage(error.data.message);
          });
      };
    

    and here is where I manage the token to call another API to get the user profile information in head:

      const dispatch = useDispatch();
      const token = useSelector((state) => state.auth.isLoggedIn);
      const userProfile = useSelector((state) => state.userProfile);
      const [postProfile] = usePostProfileMutation();
      console.log(token);
    
      useEffect(() => {
        if (token) {
          postProfile(token)
            .unwrap()
            .then((data) => {
              console.log(data);
              dispatch(setUserProfile(data.body));
            });
        }
      }, [token]);
    

    So the problem is that the state isLoggedIn which contains the token gets empty after refreshing the page.

    here is my GitHub link with full code


  2. The reason it doesn’t update is that your component is not getting a trigger to re-render unless the parent component re-renders or you hit the refresh.
    It would be a good idea to create an authSlice and maintain isLoggedIn state in the store. Once you have a token, dispatch the action to update isLoggedIn state. This, in turn, would re-render the component.

    It’s a good idea to maintain isLoggedIn state in the reducer instead of useState.

    Hope this helps.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search