CRA Boilerplate Cannot read property 'initialLoad' of undefined In Redux -Saga & Reselect & redux-toolkit

130 Views Asked by At

Getting This Error When i use a useSelector hook to fetch data. Im getting initial state undefined which cause the error.

selector.ts

import { createSelector } from '@reduxjs/toolkit';
import { RootState } from 'types';
import { initialState } from '.';

const selectSlice = (state: RootState) => state.initialLoad || initialState;
export const selectInitialLoad = createSelector([selectSlice], state => state);

index.ts

import { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from 'utils/@reduxjs/toolkit';
import { useInjectReducer, useInjectSaga } from 'utils/redux-injectors';
import { initialLoadSaga } from './saga';
import { InitialLoadState, RepoErrorType } from './types';

export const initialState: InitialLoadState = {
  name: 'initial-load',
  layouts: [],
  loading: false,
  error: null,
};

const slice = createSlice({
  name: 'initialLoad',
  initialState,
  reducers: {
    loadLayout(state) {
      state.loading = true;
      state.error = null;
      state.layouts = [];
    },
    layoutLoaded(state, action: PayloadAction<[]>) {
      const repos = action.payload;
      state.layouts = repos;
      state.loading = false;
    },
    layoutError(state, action: PayloadAction<string | RepoErrorType>) {
      state.error = 'error';
      state.loading = false;
    },
  },
});

export const { actions: appLayoutActions } = slice;

export const useAppLayoutSlice = () => {
  useInjectReducer({ key: slice.name, reducer: slice.reducer });
  useInjectSaga({ key: slice.name, saga: initialLoadSaga });
  return { actions: slice.actions };
};

types.ts

/* --- STATE --- */
export interface InitialLoadState {
  name: string;
  loading: boolean;
  error?: RepoErrorType | string | null;
  layouts: [];
}
export enum RepoErrorType {
  RESPONSE_ERROR = 1,
  USER_NOT_FOUND = 2,
  USERNAME_EMPTY = 3,
  USER_HAS_NO_REPO = 4,
  GITHUB_RATE_LIMIT = 5,
}

/* 
  If you want to use 'ContainerState' keyword everywhere in your feature folder, 
  instead of the 'InitialLoadState' keyword.
*/
export type ContainerState = InitialLoadState;

reducers.ts

/**
 * Combine all reducers in this file and export the combined reducers.
 */

import { combineReducers } from '@reduxjs/toolkit';

import { InjectedReducersType } from 'utils/types/injector-typings';

/**
 * Merges the main reducer with the router state and dynamically injected reducers
 */
export function createReducer(injectedReducers: InjectedReducersType = {}) {
  // Initially we don't have any injectedReducers, so returning identity function to avoid the error
  if (Object.keys(injectedReducers).length === 0) {
    return state => state;
  } else {
    return combineReducers({
      ...injectedReducers,
    });
  }
}

this is my configuerStore.ts

    /**
 * Create the store with dynamic reducers
 */

import {
  configureStore,
  getDefaultMiddleware,
  StoreEnhancer,
} from '@reduxjs/toolkit';
import { createInjectorsEnhancer } from 'redux-injectors';
import createSagaMiddleware from 'redux-saga';

import { createReducer } from './reducers';

export function configureAppStore() {
  const reduxSagaMonitorOptions = {};
  const sagaMiddleware = createSagaMiddleware(reduxSagaMonitorOptions);
  const { run: runSaga } = sagaMiddleware;

  // Create the store with saga middleware
  const middlewares = [sagaMiddleware];

  const enhancers = [
    createInjectorsEnhancer({
      createReducer,
      runSaga,
    }),
  ] as StoreEnhancer[];

  const store = configureStore({
    reducer: createReducer(),
    middleware: [...getDefaultMiddleware(), ...middlewares],
    devTools: process.env.NODE_ENV !== 'production',
    enhancers,
  });

  return store;
}

work around adding a condition to state

import { createSelector } from '@reduxjs/toolkit';
import { RootState } from 'types';
import { initialState } from '.';

const selectSlice = (state: RootState) => state && state.initialLoad || initialState;
export const selectInitialLoad = createSelector([selectSlice], state => state);

most of the files are of create react app boilerplate not change. i tried the same on the cra boilerplate template without clean setup and it worked fine but after clean and setup it doesnt work how i need it too

1

There are 1 best solutions below

1
Khoa Tran On

Please define initialLoad into /src/types/RootState.ts

Example here

1