I have made a simple react app with the sample code from the following blogpost, which I leave only as a citation. I am otherwise new to the javascript ecosystem and am trying to fit together several unfamiliar tools (in order to learn them).
Relevantly, my store.js
looks like this:
import { createStore, applyMiddleware, compose, } from 'redux';
import { connectRouter, routerMiddleware, } from 'connected-react-router';
import thunk from 'redux-thunk';
import { install, } from 'redux-loop';
import createHistory from 'history/createBrowserHistory';
import rootReducer from './modules';
export const history = createHistory();
const initialState = {};
const middleWare = [thunk, routerMiddleware(history),];
const composedEnhancers = compose(
applyMiddleware(...middleWare),
install()
);
const store = createStore(
connectRouter(history)(rootReducer),
initialState,
composedEnhancers
);
export default store;
This seems to work fine, and the Link
/Route
triggers on my page work fine. Note that install
from redux-loop
is being called as part of an enhancer (?) and this is fine. I do not have any loop
calls in my reducers, I just inserted the install
command as an enhancer with the hope that I will be able to add some.
Here is my main reducer
code:
import { combineReducers, } from 'redux';
import counter from './counter';
import todo from './todo';
export default combineReducers({
counter,
todo,
});
Again, this works great. However, if I insert loop
anywhere in my reducers, it dies. According to the docs, this is because we need to use the combineReducers
from redux-loop
. Fine. If I replace the import at the top to import { combineReducers, } from 'redux-loop';
(not altering my reducers at all, there are no nonstandard returns yet) then I get some completely nonsensical errors in library code:
ConnectedRouter.js:58 Uncaught TypeError: Cannot read property 'pathname' of undefined
at ConnectedRouter.js:58
at Object.dispatch (redux.js:221)
at dispatch (install.js:66)
at middleware.js:25
at index.js:11
at Object.onLocationChanged (ConnectedRouter.js:154)
at handleLocationChange (ConnectedRouter.js:85)
at new ConnectedRouter (ConnectedRouter.js:94)
at constructClassInstance (react-dom.development.js:11769)
at updateClassComponent (react-dom.development.js:13491)
at beginWork (react-dom.development.js:14090)
at performUnitOfWork (react-dom.development.js:16416)
at workLoop (react-dom.development.js:16454)
at renderRoot (react-dom.development.js:16533)
at performWorkOnRoot (react-dom.development.js:17387)
at performWork (react-dom.development.js:17295)
at performSyncWork (react-dom.development.js:17267)
at requestWork (react-dom.development.js:17155)
at scheduleWork (react-dom.development.js:16949)
at scheduleRootUpdate (react-dom.development.js:17637)
at updateContainerAtExpirationTime (react-dom.development.js:17664)
at updateContainer (react-dom.development.js:17691)
at ReactRoot../node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render (react-dom.de...
It goes on for many pages, but the issue seems to be in ConnectedRouter
; I assume this is because combineReducers
in redux-loop
changes the response type of the main reducer into something that's not compatible with the connectRouter(history)(rootReducer)
in the createStore
call.
Is this the right issue? Is this fixable? Can these two libraries be used together?
There's an open issue that would address this, but until that is done it requires a hack. I called combineReducers with something like this (I am using immutable js. but if you're not it's simple to convert to that)
import { connectRouter } from 'connected-react-router/immutable';
import { Map } from 'immutable';
//....
const routerReducer = connectRouter(history)(() => fromJS({}));
return combineReducers(
{
foo: fooReducer,
blah: blahReducer,
router: (state, action) => {
const routerStateWrapper = Map({router: state});
const result = routerReducer(routerStateWrapper, action);
return result.get('router');
}
}
)