Search code examples
javascripthtmlreactjsredux

Getting an error when combining two reducers using combineReducers()


I'm trying to create separate reducers for different React components. This is the code:

store.tsx:

const store = createStore(rootReducer, composeWithDevTools());

root.reducers.tsx:

import { combineReducers } from 'redux';
import mainReducer from './main.reducers';
import profileReducers from './components/Profile/Profile.reducers';

const rootReducer = combineReducers({
    mainReducer,
    profileReducers,
});

export default rootReducer;

main.reducers.tsx:

<...>
function mainReducer(state = initialState, action: AnyAction) {
    switch (action.type) {
        case HOME_PAGE_MOVIES_ADDED:
            return {
                ...state,
                homePageMovies: action.homePageMovies,
            };
        case MOVIE_SELECTED:
            return {
                ...state,
                selectedMovie: action.selectedMovie,
            };

        default:
            return state;

export default mainReducer;
export type RootState = ReturnType<typeof mainReducer>;

profile.reducers.tsx:


interface mainState {
    selectedCategory: boolean;
}

const initialState: mainState = {
    selectedCategory: false,
};

function profileReducers(state = initialState, action: AnyAction) {
    switch (action.type) {
        case CATEGORY_SELECTED:
            return {
                ...state,
                selectedCategory: action.selectedCategory,
            };
        default:
            return state;
    }
}

export default profileReducers;
export type RootState = ReturnType<typeof profileReducers>;

When I try to render UI, I get following error: enter image description here

enter image description here

I get this error once I replace mainReducer by rootReducer at */store.tsx > const store = createStore(mainReducer, composeWithDevTools());.

What am i missing? Thanks!


Solution

  • It seems prior to using the combineReducers function to create/merge/expand your redux store's state tree you had just the single reducer.

    const store = createStore(mainReducer, composeWithDevTools());
    

    As such the state that mainReducer handled was your app's state.

    const favoriteMoviesAll = useSelector(
      (state: RootState) => state.homePageMovies
    );
    

    When you start expanding the state tree you are now nesting reducers under specific keys.

    const rootReducer = combineReducers({
      mainReducer,
      profileReducers,
    });
    
    const store = createStore(rootReducer, composeWithDevTools());
    

    Now the root state is an object with mainReducer and profileReducers properties. state.homePageMovies is undefined.

    const favoriteMoviesAll = useSelector(
      (state: RootState) => state.homePageMovies // undefined
    );
    

    Now favoriteMoviesAll is also undefined and can't access any slice method.

    const favoriteMovies = favoriteMoviesAll.slice(0, 19); // throws error!
    

    The same previous state that was state.homePageMovies is now nested deeper in state.mainReducer.homePageMovies.

    const favoriteMoviesAll = useSelector(
      (state: RootState) => state.mainReducer.homePageMovies
    );
    

    Since this is the way react-redux works, and the naming convention for the reducer functions is <state-area>Reducer it's common to rename the reducers being passed to combineReducers to give them more readable names that make sense in a state tree.

    Example:

    const rootReducer = combineReducers({
      movies: mainReducer,
      profile: profileReducers,
    });
    

    ...

    const favoriteMoviesAll = useSelector(
      (state: RootState) => state.movies.homePageMovies
    );