Реагировать на горячую перезагрузку с помощью Redux

У меня все работает с HMR / React Hot Reloader, что касается представлений. Но после добавления redux, react-redux и т. д. каждый раз, когда я изменяю представление или редуктор, я получаю следующую ошибку:

<Provider> does not support changing `store` on the fly. It is most likely that you see this error because you updated to Redux 2.x and React Redux 2.x which no longer hot reload reducers automatically. See https://github.com/reactjs/react-redux/releases/tag/v2.0.0 for the migration instructions.

Переход по ссылке в ошибке приводит к сообщению двухлетней давности о явном использовании replaceReducer, что я и сделал.

Мои версии:

«редукс»: «^ 3.7.2» «реагировать-редукс»: «^ 5.0.6»

У меня такое ощущение, что это в основном связано с моим непониманием того, где и как размещать вызовы module.hot.accept (и можно ли их иметь несколько?). Соответствующий код ниже.

boot.js (точка входа)

import { Provider } from 'react-redux';
import { AppContainer } from 'react-hot-loader';
import { ConnectedRouter } from 'react-router-redux';

import App from './App';

import { configureStore, history } from './store/configureStore';

let store = configureStore();

function renderApp() {
    ReactDOM.render(
      <AppContainer>
        <Provider store={store}>
          <ConnectedRouter history={history}>
            <App />
          </ConnectedRouter>
        </Provider>
      </AppContainer>
      , document.getElementById("app"));
}

renderApp();

if (module.hot) {
    module.hot.accept(() => {
        renderApp();
    })
}

configureStore.js

import createHistory from 'history/createBrowserHistory';
import { createStore, combineReducers, compose, applyMiddleware } from 'redux';
import { routerMiddleware, routerReducer } from 'react-router-redux';
import thunk from 'redux-thunk';

import DevTools from '../components/DevTools';

import * as rootReducer from '../services/rootReducer';

const composeEnhancers = compose;

export const history = createHistory();

const middleware = routerMiddleware(history);

export function configureStore(initialState) {
  const reducers = { ...rootReducer, router: routerReducer };

  const store =  createStore(
    combineReducers(reducers),
    initialState,
    composeEnhancers(
      applyMiddleware(middleware, thunk),
      DevTools.instrument()
    )
  );

  if (module.hot) {
    module.hot.accept('../services/rootReducer', () => {
      const nextRootReducer = require('../services/rootReducer').default;
      const finalReducer = {...nextRootReducer, router: routerReducer };
      store.replaceReducer(finalReducer);
    })
  }

  return store;
}

Module.hot.accept в моем configureStore на самом деле никогда не вызывается, потому что вызывается родительский модуль в boot.js. Может быть только 1?!

Как избавиться от этой ошибки?

Или, позвольте мне перефразировать: как мне избавиться от этой ошибки и правильно настроить среду горячей загрузки с редукционными хранилищами?

Возможно актуальная проблема Github:

https://github.com/reactjs/react-redux/issues/259


person Jack    schedule 17.11.2017    source источник


Ответы (1)


После дальнейших исследований выяснилось, что проблема была связана с областью вызова accept в boot.js. Поскольку оно, по сути, наблюдало за ВСЕМ из приложения корневого уровня, все приложение было перезагружено при изменении редуктора, поэтому прием HMR редуктора никогда не вызывался. Ниже рабочая версия.

boot.js

if (module.hot) {
    module.hot.accept('./containers/App.js', () => {
        const nextApp = require('./containers/App').default;
        renderApp(nextApp);
    })
}

configureStore.js

  if (module.hot) {
    module.hot.accept('../services/rootReducer', () => {
      const nextRootReducer = require('../services/rootReducer');
      const finalReducer = {...nextRootReducer, router: routerReducer };
      store.replaceReducer(combineReducers(finalReducer));
    })
  }
person Jack    schedule 18.11.2017