简体   繁体   中英

How to organize state with redux and react-router?

Redux advocates the use of a single store with a single state. However, with react-router you get multiple pages each having their own top-level root component.

How should one go about wiring up redux with a react-router app that has multiple pages? React-router 1.0 no longer lets you pass props to the routes so making the router the top level component that contains the state for all the pages is no longer possible nor is it feasible.

If you are using redux + react-router I would highly recommend using redux-router as well - this will allow you to keep route information in your store - I usually have the following setup.

redux-router: ^1.0.0-beta3 / react-router": ^1.0.0-rc1 / redux: "^3.0.2 / react: "^0.14.0

//index.js [entry point]

import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route } from 'react-router';
import { Provider } from 'react-redux';
import createStore from './utils/create-store';
import routes from './bootstrap/routes';
import { ReduxRouter } from 'redux-router';

const store = createStore(routes);

ReactDOM.render(
    <Provider store={store}>
        <ReduxRouter>
            {routes}
        </ReduxRouter>
    </Provider>,
    document.getElementById('root')
);

// create-store.js

import { applyMiddleware, createStore, combineReducers, compose } from 'redux';
import * as reducers from '../reducers/index';
import promiseMiddleware from './promise-middleware';
import { routerStateReducer, reduxReactRouter } from 'redux-router';
import history from './history'

/**
 * Sets up the redux store.  Responsible for loading up the reducers and middleware.
 *
 * @param routes
 */
export default function create(routes) {
    const composedReducers = combineReducers({
        router: routerStateReducer,
        ...reducers
    });
    const finalCreateStore = compose(applyMiddleware(promiseMiddleware),
        reduxReactRouter({
            routes,
            history
        }))(createStore);
    let store = finalCreateStore(composedReducers);
    return store;
}

// routes.js

import React from 'react';
import { Route } from 'react-router';
import  App from './app';

module.exports = (
    <Route component={App}>
        ...all your routes go here
    </Route>
);

// app.js

import React, { PropTypes } from 'react';
import { connect } from 'react-redux';

export default class App extends React.Component {

    render() {
        const { props: { children } } = this;
        return (
            <div className="app-container">
              {children}
            </div>
        );
    }
}

So as you can see there is one higher order component that wraps the rest of your routes

Redux-router is no longer compatible with react-router v4, and the above solution will not work.

As such, I suggest utilzing redux-little-router . Unlike redux-router it is not dependent on react-router, but instead a replacement for it.

With it you can do things like:

Push to new routes from your async actions:

export function navigateAbout() {
  return (dispatch) => {
    dispatch(push('/about'))
  }
}

See your router details (current path, querystring and params) inside redux-dev-tools, and access those details from you store like you would for any other prop:

function mapStateToProps(state) {
  return {
    string: state.router.query.string
  }
}

PS. You can refer to or use this react boilerplate with redux-little-redux already implemented

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM