I’m using a reducer to set the state in Redux. My state currently looks something like this.
{
activeConversation: "Jim"
conversations: (7) [{…}, {…}, {…}, {…}, {…}, {…}, {…}]
user: {id: 8, username: "josh", email: ""}
}
In my old reducer, I was just getting the conversations array and setting that but now I need access to the activeConversation string as well. Therefore, I decided to use my root reducer which combines everything so it can work correctly. Here’s my root reducer.
import { createStore, applyMiddleware, combineReducers } from "redux";
import loggerMiddleware from "redux-logger";
import thunkMiddleware from "redux-thunk";
import user from "./user";
import conversations from "./conversations";
import activeConversation from "./activeConversation";
import {
addMessageToStore,
} from "./utils/reducerFunctions";
const CLEAR_ON_LOGOUT = "CLEAR_ON_LOGOUT";
const SET_MESSAGE = "SET_MESSAGE";
export const clearOnLogout = () => {
return {
type: CLEAR_ON_LOGOUT
};
};
export const setNewMessage = (message, sender) => {
return {
type: SET_MESSAGE,
payload: { message, sender: sender || null },
};
};
const appReducer = combineReducers({
user,
conversations,
activeConversation
});
const rootReducer = (state, action) => {
if (action.type === CLEAR_ON_LOGOUT) {
state = undefined;
} else if (action.type === SET_MESSAGE) {
return addMessageToStore(state, action.payload);
}
return appReducer(state, action);
};
export default createStore(rootReducer, applyMiddleware(thunkMiddleware, loggerMiddleware));
My setNewMessage function is called which then calls addMessageToStore
.
export const addMessageToStore = (state, payload) => {
const { message, sender } = payload;
return { state, conversations: state.conversations.map((convo) => {
if (convo.id === message.conversationId) {
const newUnread = convo.unreadMessages;
if (state.activeConversation === convo.otherUser) {
newUnread = (parseInt(newUnread) + 1).toString();
}
const newConvo = {
convo,
messages: convo.messages.concat(message),
latestMessageText: convo.latestMessageText,
unreadMessages: newUnread
}
console.log("newConvo:", {state, conversations: newConvo});
return {state, conversations: newConvo};
} else {
return {state, conversations: convo};
}
})};
};
The problem with this is that next state
isn’t being updated. When it returns next state
, it just shows the previous state instead of my new one. Does anyone know what’s going on?
Advertisement
Answer
I think you are “cutting” your state slices inefficiently. At best, a Reducer should always own their own state, and you are right now going to great lengths to have a meta-reducer for conversations
to have access to the activeConversation
.
Why not have a normal reducer for both?
Have a state of the shape
{
user,
conversations
}
where conversations
has the shape
{
items,
active
}
That way your conversations
reducer has just access to it’s own state properties – items
and active
– and does not need to to any gymnastics.