react-admin: admin state created in store but doesn't update on any crud operation

Viewed 752

I'm working with react-admin for the first ever time. I have a custom react application and want to use react-admin inside it. Following the tutorial, I found that I probably don't need to do anything as I am using the <Admin> component and the admin is supposed to detect that its inside a redux application and mount its state under the admin key in the store. Seems like the initial state is being created. But it doesn't update ever. Also I see no actions related to react-admin like RA/REGISTER_RESOURCE in redux dev tools.

enter image description here

My default createStore.js is (its from react-boilerplate)

import { createStore, applyMiddleware, compose } from 'redux';
import { routerMiddleware } from 'connected-react-router';
import createSagaMiddleware from 'redux-saga';
import createReducer from './reducers';

export default function configureStore(initialState = {}, history) {
  let composeEnhancers = compose;
  const reduxSagaMonitorOptions = {};

  if (process.env.NODE_ENV !== 'production' && typeof window === 'object') {
    if (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__)
      composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
        trace: true,
        traceLimit: 25,
      });
  }

  const sagaMiddleware = createSagaMiddleware(reduxSagaMonitorOptions);

  const middlewares = [sagaMiddleware, routerMiddleware(history)];

  const enhancers = [applyMiddleware(...middlewares)];

  const store = createStore(
    createReducer(),
    initialState,
    composeEnhancers(...enhancers),
  );

  store.runSaga = sagaMiddleware.run;
  store.injectedReducers = {}; // Reducer registry
  store.injectedSagas = {}; // Saga registry

  // Make reducers hot reloadable, see http://mxs.is/googmo
  /* istanbul ignore next */
  if (module.hot) {
    module.hot.accept('./reducers', () => {
      store.replaceReducer(createReducer(store.injectedReducers));
    });
  }

  return store;
}

I have also tried

import { routerMiddleware } from 'connected-react-router';
import createSagaMiddleware from 'redux-saga';
import { all, fork } from 'redux-saga/effects';
import createReducer from './reducers';

import { adminSaga, USER_LOGOUT } from 'react-admin';

export default ({ authProvider, dataProvider, history }) => {
  const reducer = createReducer();
  const resettableAppReducer = (state, action) =>
    reducer(action.type !== USER_LOGOUT ? state : undefined, action);

  const saga = function* rootSaga() {
    yield all([adminSaga(dataProvider, authProvider)].map(fork));
  };
  const sagaMiddleware = createSagaMiddleware();

  const composeEnhancers =
    (process.env.NODE_ENV === 'development' &&
      typeof window !== 'undefined' &&
      window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ &&
      window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
        trace: true,
        traceLimit: 25,
      })) ||
    compose;

  const store = createStore(
    resettableAppReducer,
    {},
    composeEnhancers(
      applyMiddleware(sagaMiddleware, routerMiddleware(history)),
    ),
  );
  sagaMiddleware.run(saga);

  store.runSaga = sagaMiddleware.run;
  store.injectedReducers = {}; // Reducer registry
  store.injectedSagas = {}; // Saga registry

  if (module.hot) {
    module.hot.accept('./reducers', () => {
      store.replaceReducer(createReducer(store.injectedReducers));
    });
  }
  return store;
};


where reducers.js is

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

import { combineReducers } from 'redux';
import { connectRouter } from 'connected-react-router';
import { reducer as formReducer } from 'redux-form';

import history from 'utils/history';
import languageProviderReducer from 'containers/LanguageProvider/reducer';
import profilePageReducer from 'containers/ProfilePage/reducer';
import { adminReducer } from 'react-admin';

export default function createReducer(injectedReducers = {}) {
  const rootReducer = combineReducers({
    form: formReducer,
    language: languageProviderReducer,
    profilePage: profilePageReducer,
    admin: adminReducer,
    ...injectedReducers,
  });

  const mergeWithRouterState = connectRouter(history);
  return mergeWithRouterState(rootReducer);
}

I have tried a lot but don't seem to be able to find the problem. Any help will be much appreciated.

2 Answers

I had this issue whilst implementing React Admin in another application. Took me a while to figure out that the issue was that the boilerplate code I copied over from the React Admin docs for initialising the store meant a new store was initialised on each render:

suggested in docs:

const App = () => (
    <Provider
        store={createAdminStore({
            authProvider,
            dataProvider,
            history,
        })}
    >
        <Admin
            authProvider={authProvider}
            dataProvider={dataProvider}
            history={history}
            title="My Admin"
        >
        ...
    </Provider>
);

solution:

const store = createAdminStore({ authProvider, dataProvider, history });

const App = () => (
    <Provider
        store={store}
    >
        <Admin
            authProvider={authProvider}
            dataProvider={dataProvider}
            history={history}
            title="My Admin"
        >
        ...
    </Provider>
);

The store was fine. Everything was working. The actions were not being shown in the extension due to this bug. Ended up wasting a lot of time on this.

Edit: Not everything was fine. RA doesn't detect my store so it creates its own. The redux dev tools extension was showing the other store hence no actions from RA were shown.

Related