0
votes

Sorry for bad English.

I'm struggling with ssr(pure react) + redux + code splitting(@loadable) + injecting redux. (highly effected by react-boilerplate)

currently my code working great without preload data.

I don't know how can I handle ssr preload data before inject reducer.

here is example to help my problem is.

store = {
  global: { // default
    key: 'value' // this is done. ssr working great using this value.
  },
  injected: { // dynamically injected. using replaceReducer per page. (same with react-boilerplate)
    key: 'value' // I want to put this value on ssr preload. (not working)
  }
}

When it done, it said

Unexpected property "injected" found in previous state received by the reducer. Expected to find one of the known reducer property names instead: "global". Unexpected properties will be ignored.

I know why this error comes(because initial store does not has 'injected' store.), but I don't know How can I fix it properly.

Is there any usage example?

Here is my thought, but it seemed not proper answer.

  1. insert key for preload data on 'global'.
  2. put preload data on 'global' in server.
  3. Move global to injected store(in this case, 'injected') when injecting is done.
  4. voila!
1

1 Answers

0
votes

reducerInjector.js

export const injectState = (reducers, preloadedState = {}) =>
  Object.keys(reducers).reduce((result, key) => {
    const finalReducers = result;
    if (typeof reducers[key] === 'function') {
      finalReducers[key] = (state = preloadedState[key], action) => reducers[key](state, action);
    }
    return finalReducers;
  }, {});

export const createInitialState = (reducers, preloadedState = {}) =>
  Object.keys(preloadedState).reduce((r, key) => {
    if (!reducers[key]) return r;
    return { ...r, [key]: preloadedState[key] };
  }, {});

export const createReducer = (staticReducers, asyncReducers, preloadedState) =>
  combineReducers(injectState({
    ...staticReducers,
    ...asyncReducers,
  }, preloadedState));


export default function reducerInjector(store, staticReducers, preloadedState) {
  // Add a dictionary to keep track of the registered async reducers
  store.asyncReducers = {};

  // Create an inject reducer function
  // This function adds the async reducer, and creates a new combined reducer
  store.injectReducer = (key, asyncReducer) => {
    store.asyncReducers[key] = asyncReducer;
    store.replaceReducer(createReducer(staticReducers, store.asyncReducers, preloadedState));
  };
  return store;
}
...
import reducerInjector, { createReducer, createInitialState } from './reducerInjector';

const configureStore = (initialState, ssr) => {
  const sagaMiddleware = createSagaMiddleware({});
  const createStoreWithMiddleware = compose(applyMiddleware(thunkMiddleware, sagaMiddleware));
  const reducer = createReducer(rootReducer, {}, initialState);
  const initialData = createInitialState(rootReducer, initialState);
  let store = createStoreWithMiddleware(createStore)(reducer, initialData);
  store = reducerInjector(store, rootReducer, initialState);
  return store;
}