0

In Redux, I currently have a state that looks something like the following.

{
  activeConversation: "Jim"
  conversations: (7) [{…}, {…}, {…}, {…}, {…}, {…}, {…}]
  user: {id: 8, username: "josh", email: ""}
}

I currently have a function that adds a new message to the conversations array. Here's how it works; it starts by calling it in thunk.

export const postMessage = (body) => async (dispatch) => {
  try {
      if (!body.conversationId) {
        dispatch(addConversation(body.recipientId, data.message));
      } else {
        dispatch(setNewMessage(data.message));
      }
  } catch (error) {
    console.error(error);
  }
};

If the conversationId exists then it calls setNewMessage in Actions.

const SET_MESSAGE = "SET_MESSAGE";
export const setNewMessage = (message, sender) => {
  return {
    type: SET_MESSAGE,
    payload: { message, sender: sender || null },
  };
};

const reducer = (state = [], action) => {
  switch (action.type) {
    case SET_MESSAGE:
      return addMessageToStore(state, action.payload);
    default:
      return state;
  }
};

export default reducer;

The problem is that the state in this action only contains the conversations array and not anything else. What I need is to also have the activeConversation so I can use it in my reducer function. I'm not quite sure how states work so I don't know why only the conversations array appears in state and not anything else.

Also, here's how activeConversation is being set.

const SET_ACTIVE_CHAT = "SET_ACTIVE_CHAT";

export const setActiveChat = (username) => {
  return {
    type: SET_ACTIVE_CHAT,
    username
  };
};

const reducer = (state = "", action) => {
  switch (action.type) {
    case SET_ACTIVE_CHAT: {
      return action.username;
    }
    default:
      return state;
  }
};

I'm wondering how I can get the activeConversation state for my set message reducer function.

Josh Susa
  • 385
  • 1
  • 6
  • 13
  • Actions don't have state, but I think I understand. It sounds like you want to reference both the `activeConversation` ***and*** the `conversations` array within the same reducer function. For this the state and reducer functions should be combined, in other words, you might've split up your state a little too much. Can you describe in some detail how you want to merge and use these two state? – Drew Reese Aug 29 '21 at 18:35
  • Do you have root reducer where you combine the positions of states you make in your reduces? – Sanish Joseph Aug 29 '21 at 18:36
  • I believe I do. Should I just be using that or is there a way I can combine multiple states? – Josh Susa Aug 29 '21 at 18:40
  • As @DrewReese pointed out you need to combine the state or another approach is to pass the `activeConversation` as a payload . so that inside the reducer you can do `action.payload.activeConversation` . – Shyam Aug 29 '21 at 18:54
  • I don't necessarily want to pass it in from thunk because I need to know what the current state of ```activeConversation``` is at that particular point. I was wondering if there was a way to access the state of ```activeConversation``` from within my reducer function (note that I already imported the ```activeConversation``` reducer). – Josh Susa Aug 29 '21 at 19:00

1 Answers1

0

Thunk will give you access to the entire store as the second argument using the method getState. So you can change your action creator as

export const postMessage = (body) => async (dispatch, getState) => {
  try {
    if (!body.conversationId) {
      dispatch(addConversation(body.recipientId, data.message));
    } else {
      const { activeConversation } = getState();
      dispatch(setNewMessage(data.message, activeConversation));
    }
  } catch (error) {
    console.error(error);
  }
};

Pass the state as the payload to your action object .

export const setNewMessage = (message, activeConversation, sender) => {
  return {
    type: SET_MESSAGE,
    payload: { message, activeConversation, sender: sender || null },
  };
};

Once you have it in the action payload , you can read it inside your reducer as action.payload.activeConversation

The getState() method provided by thunk will guarantee the store state at that particular point in time . As it interally is just the call to store.getState() provided by redux .

Reference

Thunk getState

Accessing getState in action creator

Good explanation on accessing getState

Shyam
  • 5,292
  • 1
  • 10
  • 20
  • While that does get me the correct state, what I'm doing is a chat app that sends messages to another user. So, after the call in thunk, I then call ```sendMessage(data, body);`` that uses socket.io to send the data to the other user. On socket.io, it would then call ```store.dispatch(setNewMessage(data.message, data.sender))``` and if I pass in the state I got from thunk, I'm wondering if it would be the correct state for the other user. – Josh Susa Aug 29 '21 at 19:13
  • @JoshSusa give it a shot , we will not know until we try it :-) – Shyam Aug 29 '21 at 19:19
  • Does your `activeConversation` inside your thunk has any value ? . I would suggest you to check in the Redux dev tools as well whether we are seeing the `activeConversation` in the state when dispatching the action . – Shyam Aug 29 '21 at 20:03
  • 1
    Alright, I got it working but it's still the same active user for both sides. I want the active user to be different for each user. Is it possible to get the state from my conversations reducer? – Josh Susa Aug 29 '21 at 20:35