skip to Main Content

Ok so I need the message redux state to receive the message from the emailChange api call.

Im new to this so keep that in mind.

This is my function from my auth slice actions

export const emailChange = createAsyncThunk(
  "auth/emailChange",
  async ({ email, change }, thunkAPI) => {

      const data = await AuthService.emailChange({email, change})
      thunkAPI.dispatch(setMessage(data.message));
      console.log(data);
      return data; 
    })

auth slice

export const logout = createAsyncThunk("auth/logout", async () => {
  await AuthService.logout();
});

const initialState = user
  ? { isLoggedIn: true, user }
  : { isLoggedIn: false, user: null };

const authSlice = createSlice({
  name: "auth",
  initialState,
  extraReducers: {
    [register.fulfilled]: (state, action) => {
      state.isLoggedIn = false;
    },
    [register.rejected]: (state, action) => {
      state.isLoggedIn = false;
    },
    [login.fulfilled]: (state, action) => {
      state.isLoggedIn = true;
      state.user = action.payload.user;
    },
    [login.rejected]: (state, action) => {
      state.isLoggedIn = false;
      state.user = null;
    },
    [logout.fulfilled]: (state, action) => {
      state.isLoggedIn = false;
      state.user = null;
    },
  },
});

const { reducer } = authSlice;
export default reducer;

where i dispatched emailChange

 const handleSubmit = (formValue) => {
    setSuccessful(false);
    setLoading(true);
    if (change!=="email") {
    dispatch(forgottenPassword(formValue))
    .then((response) => {
        if (response.payload.status === "PENDING"){
            setSuccessful(true);
            //navigate(`/emailsent/${formValue.email}/${true}`) 
        }
            setLoading(false);
            setMessage(response.payload)
        })  
    }else if(change==="email") {
        const {email} = formValue
        const post = {change:true, email}
        dispatch(emailChange(post))
        .then((response) => {
            if (response.payload.status === "PENDING"){
                setSuccessful(true);
            } 
                setLoading(false);
                setMessage(response.payload)
                console.log(message2) //this is the message redux state
            }) 
    }       
};

api call

const emailChange = ({email, change}) => {
  return api
    .post("/auth/emailChange", {email, change})
    .then((response) => {
      return response.data;
    });
};

message slice

import { createSlice } from "@reduxjs/toolkit";

const initialState = {};

const messageSlice = createSlice({
  name: "message",
  initialState,
  reducers: {
    setMessage: (state, action) => {
      return { message: action.payload };
    },
    clearMessage: () => {
      return { message: "" };
    },
  },
});

const { reducer, actions } = messageSlice;

export const { setMessage, clearMessage } = actions
export default reducer;

Why would this code not work?

I tried and checked many different configurations.

console logs show the correct payload is being sent to message, but the state does not update

Everything is happening correctly except the message state does not update according to console log.

I’m hoping it is something obvious in this code

This function in my auth slice actions works fine

export const register = createAsyncThunk(
  "auth/register",
  async ({ username, email, password }, thunkAPI) => {
    try {
      const response = await AuthService.register(username, email, password);
      thunkAPI.dispatch(setMessage(response.data.message));
      return response.data;
    } catch (error) {
      const message =
        (error.response &&
          error.response.data &&
          error.response.data.message) ||
        error.message ||
        error.toString();
      thunkAPI.dispatch(setMessage(message));
      return thunkAPI.rejectWithValue();
    }
  }
);

2

Answers


  1. Chosen as BEST ANSWER

    So I managed to solve it. ultimately changing const
    {message2} = useSelector((state) => state.message.message); to message2 = useSelector((state) => state.message.message);

    allowed it to work.

    I also put the emailchange action in its own slice and it seemed to help but not sure.


  2. Okay so a better way to handle this is actually in the extraReducers. Heads up I personally use the "map object" notation but you can also use the builder. Here are the docs for extraReducers.

    ** Note it’s a good idea to define what your state will be initial state.
    Also you are most likely not getting the update because you are returning. Instead you should be assigning the state in your reducers i.e. in the setMessage you should do this state.message = action.payload in redux toolkit it uses immer under the hood so you can mutate state it will handle it behind the scene.

    import { createSlice } from "@reduxjs/toolkit";
    
    export const emailChange = createAsyncThunk(
      "auth/emailChange",
      async ({ email, change }, thunkAPI) => {
          const data = await AuthService.emailChange({email, change})
          // No need to dispatch the thunkAPI as it will automatically look in the extra reducers.
          return data; 
        })
    
    const initialState = {
      message: ""
    };
    
    const messageSlice = createSlice({
      name: "message",
      initialState,
      reducers: {
        setMessage: (state, action) => {
          state.message = action.payload;
        },
        clearMessage: () => {
          state.message = "";
        },
      },
      extraReducers: {
       [emailChange.pending]: (state, action) => {
         // Great place to set isLoading true.
       },
       [emailChange.fullfilled]: (state, action) => {
         // Heads up its atleast action.payload might want to check in debugger if you need to dig further into the object.
         state.message = action.payload;
         // Great place to set the isLoading false.
       },
       [emailChange.rejected]: (state, action) => {
         // Great place to set an error message to display to user or whatever.
         // Might set isLoading to false here.
       },
       [register.fulfilled]: (state, action) => {
          // Could add a string here or back in the createAsyncThunk on the return you could destructure and add a message there then do action.payload.message or whatever.
          state.message = "Login successful";
        },
     }
    
    });
    
    const { reducer, actions } = messageSlice;
    
    export const { setMessage, clearMessage } = actions
    export default reducer;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search