Search code examples
reactjsreduxreact-routerreact-reduxreact-router-redux

react-router-redux syncHistoryWithStore crash / passing state with react-router


Basically the problem is I couldn't pass the state using react-redux with react-router. In my component I have a code like this:

    export default connect(
    (state, ownProps) => ({
        reduxState: state,
        ownProps
    }),
    dispatch => ({
        onSyncState: (state) => {
            dispatch({type: 'SYNCHRONIZE_STORE', payload: state});
        }
    })
)(Home);

but when I try to console log the props I see that I have reduxState: undefined. dispatch works fine. So now I try to use react-router-redux to synchronize them.

In my index.js file I have a code like this:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import Home from './Home/Home.component';
import Edit from './Edit/Edit.component';
import './index.css';
import { Router, Route, browserHistory, Redirect, IndexRoute } from 'react-router';
import { createStore } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import { Provider } from 'react-redux';
import { syncHistoryWithStore } from 'react-router-redux';
import categoriesService from './Services/Categories.service'

const initialState = {
    tasks: categoriesService.getTasks(),
    categories: categoriesService.getCategories(),
    currentCategory: 1,
    filterString: '',
    showDone: 'show'
};

function reducer(state = initialState, action) {
    if (action.type === 'SYNCHRONIZE_STORE') {
        console.log(action.payload);
        console.log(state);
    }
}

const store = createStore(reducer, composeWithDevTools());
const history = syncHistoryWithStore(browserHistory, store);

ReactDOM.render(
    <Provider store={store}>
        <Router history={history}>
            <Redirect from="/" to="/home/1/show/" />
            <Route path="/" component={App}>
                <IndexRoute component={Home} />
                <Route path="/home/:category/:showDone(/:filter)" component={Home} />
                <Route path="/edit/:category/:task" component={Edit} />
            </Route>
            <Redirect from="*" to="/home/1/show/" />
        </Router>
    </Provider>,
  document.getElementById('root')
);

categoriesService is a mocked synchronous service that just returns mocked data arrays. When I try to do this with syncHistoryWithStore I get an error:

Uncaught TypeError: Cannot read property 'routing' of undefined
    at defaultSelectLocationState (sync.js:14)
    at syncHistoryWithStore (sync.js:37)
    at eval (index.js:62)
    at Object.<anonymous> (bundle.js:1372)
    at __webpack_require__ (bundle.js:556)
    at fn (bundle.js:87)
    at eval (multi_main:3)
    at Object.<anonymous> (bundle.js:589)
    at __webpack_require__ (bundle.js:556)
    at bundle.js:579

So, I'm out of ideas. Hope you can help to fix react-router-redux, or to pass the state somehow else. :)


Solution

  • Sorry, guys, this is just dumbness of mine. :) I'd forgotten to return state in the end of my reducer. :) And, I'd forgotten to combine reducers with routing to use it with syncHistoryWithStore. And it looks like I wasn't really know how this should even work.

    So here's the working example:

    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    import Home from './Home/Home.component';
    import Edit from './Edit/Edit.component';
    import './index.css';
    import { Router, Route, browserHistory, Redirect, IndexRoute } from 'react-router';
    import { createStore, combineReducers } from 'redux';
    import { composeWithDevTools } from 'redux-devtools-extension';
    import { Provider } from 'react-redux';
    import { syncHistoryWithStore, routerReducer } from 'react-router-redux';
    import categoriesService from './Services/Categories.service'
    
    const initialState = {
        tasks: categoriesService.getTasks(),
        categories: categoriesService.getCategories(),
        currentCategory: 1,
        filterString: '',
        showDone: 'show'
    };
    
    function reducer(state = initialState, action) {
        if (action.type === 'SYNCHRONIZE_STORE') {
            console.log(action);
            console.log(...state);
        }
        return state;
    }
    
    let combinedReducers = combineReducers({
        routing: routerReducer,
        reducer
    });
    
    const store = createStore(combinedReducers, composeWithDevTools());
    const history = syncHistoryWithStore(browserHistory, store);
    
    ReactDOM.render(
        <Provider store={store}>
            <Router history={history}>
                <Redirect from="/" to="/home/1/show/" />
                <Route path="/" component={App}>
                    <IndexRoute component={Home} />
                    <Route path="/home/:category/:showDone(/:filter)" component={Home} />
                    <Route path="/edit/:category/:task" component={Edit} />
                </Route>
                <Redirect from="*" to="/home/1/show/" />
            </Router>
        </Provider>,
      document.getElementById('root')
    );