Rematch: Connected-react-router integration issues

Created on 7 Mar 2018  路  4Comments  路  Source: rematch/rematch

Hello,

We have an app that uses connected-react-router, and I tried the minimal integration with init (from here).

Initial code

import { AppContainer } from 'react-hot-loader'
import { applyMiddleware, compose, createStore } from 'redux'
import { createBrowserHistory } from 'history'
import { routerMiddleware, connectRouter } from 'connected-react-router'
import {Provider } from 'react-redux'
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import thunk from 'redux-thunk'

import alerts from './modules/alerts'
import userInfo from './modules/userInfo'

const history = createBrowserHistory();
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const middlewares = [routerMiddleware(history), thunk];

const rootReducer = combineReducers({
    alerts: AlertsReducer,
    userInfo: UserInfoReducer
});
const store = createStore(
    connectRouter(history)(rootReducer),
    composeEnhancer(
        applyMiddleware(...middlewares)
    ),
);

const render = () => {
    ReactDOM.render(
        <AppContainer>
            <Provider store={store}>
                <App history={history}/>
            </Provider>
        </AppContainer>,
        document.getElementById('react-root')
    )
};

rematch integration

import { AppContainer } from 'react-hot-loader'
import { applyMiddleware, compose, createStore } from 'redux'
import { createBrowserHistory } from 'history'
import { routerMiddleware, connectRouter } from 'connected-react-router'
import {Provider } from 'react-redux'
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import rootReducer from './modules'
import thunk from 'redux-thunk'

import alerts from './modules/alerts'
import userInfo from './modules/userInfo'

const history = createBrowserHistory();
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const middlewares = [routerMiddleware(history), thunk];


import { init } from "@rematch/core";

const store = init({
    redux: {
        reducers: {
            alerts,
            userInfo,
        },
        middlewares: [...middlewared]
    },
});
// const store = createStore(
//     connectRouter(history)(rootReducer),
//     composeEnhancer(
//         applyMiddleware(...middlewares)
//     ),
// );



const render = () => {
    ReactDOM.render(
        <AppContainer>
            <Provider store={store}>
                <App history={history}/>
            </Provider>
        </AppContainer>,
        document.getElementById('react-root')
    )
};

We get some errors from the components themselves (regarding missing location from connected-react-router), but I think the main issue is this one

ConnectedRouter.js:58 Uncaught (in promise) TypeError: Cannot read property 'pathname' of undefined
    at ConnectedRouter.js:58
    at Object.p [as dispatch] (rematch.prod.min.js:34)
    at dispatch (<anonymous>:1:38399)
    at index.js:14
    at middleware.js:25
    at rematch.prod.min.js:122
    at rematch.prod.min.js:116
    at Object.next (rematch.prod.min.js:117)
    at rematch.prod.min.js:99
    at new Promise (<anonymous>)
question

Most helpful comment

After some digging the the connected-react-router code, I realized that the problem is connectRouter. This rewrites the global reducer function to a new one, but rematch needs an object with a function for each reducer.
I managed to make a individual router reducer like so, and the application works again 馃槃:

const merge = (state, payload) => ({ ...state, ...payload });
const routerReducer = (history) => {
    const initialState = {
        location: history.location,
        action: history.action,
    };
    return (state = initialState, { type, payload } = {}) => {
        if (type === LOCATION_CHANGE) {
            return merge(state, payload)
        }

        return state
    }
};


import { init } from "@rematch/core";

const store = init({
    redux: {
        reducers: {
            alerts,
            userInfo,
            router: routerReducer(history)
        },
        middlewares: [...middlewares]
    },
});

Can a function be used in [redux][reducers] instead of an object? Is it maybe another keyword?

All 4 comments

After some digging the the connected-react-router code, I realized that the problem is connectRouter. This rewrites the global reducer function to a new one, but rematch needs an object with a function for each reducer.
I managed to make a individual router reducer like so, and the application works again 馃槃:

const merge = (state, payload) => ({ ...state, ...payload });
const routerReducer = (history) => {
    const initialState = {
        location: history.location,
        action: history.action,
    };
    return (state = initialState, { type, payload } = {}) => {
        if (type === LOCATION_CHANGE) {
            return merge(state, payload)
        }

        return state
    }
};


import { init } from "@rematch/core";

const store = init({
    redux: {
        reducers: {
            alerts,
            userInfo,
            router: routerReducer(history)
        },
        middlewares: [...middlewares]
    },
});

Can a function be used in [redux][reducers] instead of an object? Is it maybe another keyword?

You really hacked this one out. Your final working solution looks quite clean. Nice work.

Good question. At this point reducers is only an object of key/functions.

There is a concept of rootReducers that you might have found interesting.

Thanks, I'll look into that in case I'll need another library that integrates in a similar way.
Awesome project, by the way, it reduces all that usual boilerplate :smiley:

How and from where to invoke LOCATION_CHANGE action?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

777PolarFox777 picture 777PolarFox777  路  3Comments

gpolonus picture gpolonus  路  3Comments

ghost picture ghost  路  5Comments

ShMcK picture ShMcK  路  4Comments

kertul picture kertul  路  4Comments