Convert Figma logo to code with AI

reactjs logoreact-router-redux

Ruthlessly simple bindings to keep react-router and redux in sync

7,816
647
7,816
1

Top Related Projects

Declarative routing for React

6,895

2,067

🧭 Declarative, asynchronous routing for React.

6,666

🥢 A minimalist-friendly ~2.1KB routing for React and Preact

🎖 seamless redux-first routing -- just dispatch actions

Quick Overview

React Router Redux is a library that provides bindings between React Router and Redux, allowing synchronization of routing data with the Redux store. It helps manage the state of the router in a Redux application, making it easier to access and manipulate routing information within the Redux ecosystem.

Pros

  • Seamless integration of React Router with Redux
  • Enables access to routing information in any connected component
  • Facilitates time-travel debugging with routing state
  • Provides a consistent way to handle routing in complex Redux applications

Cons

  • Adds complexity to the application, especially for simpler projects
  • Increases bundle size due to additional dependencies
  • May be unnecessary for applications that don't require deep integration between routing and state management
  • Has been deprecated in favor of Connected React Router or Redux-First Router

Code Examples

  1. Configuring the store with routing:
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { routerReducer, routerMiddleware } from 'react-router-redux';
import createHistory from 'history/createBrowserHistory';

const history = createHistory();
const store = createStore(
  combineReducers({
    ...reducers,
    router: routerReducer
  }),
  applyMiddleware(routerMiddleware(history))
);
  1. Connecting React Router with Redux:
import { ConnectedRouter } from 'react-router-redux';

ReactDOM.render(
  <Provider store={store}>
    <ConnectedRouter history={history}>
      <App />
    </ConnectedRouter>
  </Provider>,
  document.getElementById('root')
);
  1. Dispatching navigation actions:
import { push } from 'react-router-redux';

// In a connected component
const mapDispatchToProps = (dispatch) => ({
  navigateToHome: () => dispatch(push('/home'))
});

Getting Started

To use React Router Redux in your project:

  1. Install the package:

    npm install react-router-redux
    
  2. Set up your Redux store with the router reducer and middleware:

    import { createStore, combineReducers, applyMiddleware } from 'redux';
    import { routerReducer, routerMiddleware } from 'react-router-redux';
    import createHistory from 'history/createBrowserHistory';
    
    const history = createHistory();
    const store = createStore(
      combineReducers({
        ...reducers,
        router: routerReducer
      }),
      applyMiddleware(routerMiddleware(history))
    );
    
  3. Wrap your app with ConnectedRouter:

    import { ConnectedRouter } from 'react-router-redux';
    
    ReactDOM.render(
      <Provider store={store}>
        <ConnectedRouter history={history}>
          <App />
        </ConnectedRouter>
      </Provider>,
      document.getElementById('root')
    );
    

Competitor Comparisons

Declarative routing for React

Pros of React Router

  • More active development and maintenance
  • Better integration with modern React features (hooks, context)
  • Improved performance and smaller bundle size

Cons of React Router

  • Requires learning new API if migrating from react-router-redux
  • Less direct integration with Redux (if using Redux for state management)

Code Comparison

React Router:

import { BrowserRouter, Route, Switch } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Switch>
        <Route path="/" exact component={Home} />
        <Route path="/about" component={About} />
      </Switch>
    </BrowserRouter>
  );
}

React Router Redux:

import { ConnectedRouter } from 'react-router-redux';
import { Route, Switch } from 'react-router';

function App({ history }) {
  return (
    <ConnectedRouter history={history}>
      <Switch>
        <Route path="/" exact component={Home} />
        <Route path="/about" component={About} />
      </Switch>
    </ConnectedRouter>
  );
}

The main difference is that React Router uses the BrowserRouter component, while React Router Redux uses ConnectedRouter with a history prop. React Router's approach is more straightforward and doesn't require additional setup with Redux.

6,895

Pros of Reach Router

  • Simpler API with less boilerplate code
  • Built-in accessibility features
  • Better support for nested routing

Cons of Reach Router

  • Less mature ecosystem and community support
  • Fewer advanced features for complex routing scenarios
  • Limited integration with state management libraries

Code Comparison

React Router Redux:

import { ConnectedRouter } from 'react-router-redux'
import { Route } from 'react-router'

<ConnectedRouter history={history}>
  <Route exact path="/" component={Home} />
  <Route path="/about" component={About} />
</ConnectedRouter>

Reach Router:

import { Router } from '@reach/router'

<Router>
  <Home path="/" />
  <About path="about" />
</Router>

React Router Redux requires more setup and configuration, especially when integrating with Redux. Reach Router offers a more straightforward approach with less code and implicit route matching.

Reach Router's API is more declarative and easier to understand for beginners. However, React Router Redux provides more flexibility for complex routing scenarios and better integration with state management libraries like Redux.

Both libraries have their strengths, and the choice between them depends on the specific needs of your project, such as complexity, state management requirements, and desired level of control over routing behavior.

2,067

🧭 Declarative, asynchronous routing for React.

Pros of Navi

  • Built-in code splitting and asynchronous route loading
  • Supports declarative data fetching within route definitions
  • Simpler API with less boilerplate code required

Cons of Navi

  • Smaller community and ecosystem compared to React Router Redux
  • Less documentation and fewer third-party resources available
  • May require a steeper learning curve for developers familiar with React Router

Code Comparison

Navi:

import { createBrowserNavigation } from 'navi';

const routes = {
  '/': async () => ({
    view: <HomePage />
  }),
  '/about': async () => ({
    view: <AboutPage />
  })
};

const navigation = createBrowserNavigation({ routes });

React Router Redux:

import { createStore, combineReducers } from 'redux';
import { routerReducer, routerMiddleware } from 'react-router-redux';

const store = createStore(
  combineReducers({
    router: routerReducer
  }),
  applyMiddleware(routerMiddleware(history))
);

Key Differences

  • Navi focuses on simplicity and built-in async support
  • React Router Redux integrates closely with Redux for state management
  • Navi uses a more declarative approach to route definition
  • React Router Redux requires additional setup for Redux integration
6,666

🥢 A minimalist-friendly ~2.1KB routing for React and Preact

Pros of wouter

  • Lightweight and minimalistic, with a smaller bundle size
  • Simple API that's easy to understand and use
  • No external dependencies, reducing potential conflicts

Cons of wouter

  • Less feature-rich compared to react-router-redux
  • May require additional custom logic for complex routing scenarios
  • Smaller community and ecosystem support

Code Comparison

react-router-redux:

import { ConnectedRouter } from 'react-router-redux'
import { Route } from 'react-router'

<ConnectedRouter history={history}>
  <Route exact path="/" component={Home} />
  <Route path="/about" component={About} />
</ConnectedRouter>

wouter:

import { Router, Route } from 'wouter'

<Router>
  <Route path="/" component={Home} />
  <Route path="/about" component={About} />
</Router>

The code comparison shows that wouter has a simpler setup, without the need for a separate history object. Both libraries use similar Route components for defining paths and associated components. However, react-router-redux provides more advanced features like the ConnectedRouter, which integrates with Redux for state management. Wouter's approach is more straightforward, making it easier to get started with basic routing needs, but may require additional work for more complex scenarios.

🎖 seamless redux-first routing -- just dispatch actions

Pros of redux-first-router

  • Simplifies routing by treating it as a first-class Redux citizen
  • Provides a more declarative approach to routing
  • Allows for easier server-side rendering and code splitting

Cons of redux-first-router

  • Steeper learning curve for developers familiar with traditional routing
  • Less widespread adoption compared to React Router
  • May require more boilerplate code for complex routing scenarios

Code Comparison

react-router-redux:

import { Route } from 'react-router-dom'
import { ConnectedRouter } from 'react-router-redux'

<ConnectedRouter history={history}>
  <Route exact path="/" component={Home} />
  <Route path="/about" component={About} />
</ConnectedRouter>

redux-first-router:

import { connectRoutes } from 'redux-first-router'

const routesMap = {
  HOME: '/',
  ABOUT: '/about'
}

const { reducer, middleware, enhancer } = connectRoutes(routesMap)

The main difference is that redux-first-router uses a routes map object and integrates directly with Redux, while react-router-redux relies on React Router's component-based approach. redux-first-router's approach can lead to more centralized and Redux-centric routing logic, potentially simplifying state management in complex applications. However, react-router-redux may be more familiar to developers accustomed to traditional React routing patterns.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Project Deprecated

This project is no longer maintained. For your Redux <-> Router syncing needs with React Router 4+, please see one of these libraries instead:


⚠️ This repo is for react-router-redux 4.x, which is only compatible with react-router 2.x and 3.x

react-router-redux

npm version npm downloads build status

Keep your router in sync with application state :sparkles:

Formerly known as redux-simple-router

You're a smart person. You use Redux to manage your application state. You use React Router to do routing. All is good.

But the two libraries don't coordinate. You want to do time travel with your application state, but React Router doesn't navigate between pages when you replay actions. It controls an important part of application state: the URL.

This library helps you keep that bit of state in sync with your Redux store. We keep a copy of the current location hidden in state. When you rewind your application state with a tool like Redux DevTools, that state change is propagated to React Router so it can adjust the component tree accordingly. You can jump around in state, rewinding, replaying, and resetting as much as you'd like, and this library will ensure the two stay in sync at all times.

This library is not necessary for using Redux together with React Router. You can use the two together just fine without any additional libraries. It is useful if you care about recording, persisting, and replaying user actions, using time travel. If you don't care about these features, just use Redux and React Router directly.

Installation

npm install --save react-router-redux

How It Works

This library allows you to use React Router's APIs as they are documented. And, you can use redux like you normally would, with a single app state. The library simply enhances a history instance to allow it to synchronize any changes it receives into application state.

history + store (redux) → react-router-redux → enhanced historyreact-router

Tutorial

Let's take a look at a simple example.

import React from 'react'
import ReactDOM from 'react-dom'
import { createStore, combineReducers } from 'redux'
import { Provider } from 'react-redux'
import { Router, Route, browserHistory } from 'react-router'
import { syncHistoryWithStore, routerReducer } from 'react-router-redux'

import reducers from '<project-path>/reducers'

// Add the reducer to your store on the `routing` key
const store = createStore(
  combineReducers({
    ...reducers,
    routing: routerReducer
  })
)

// Create an enhanced history that syncs navigation events with the store
const history = syncHistoryWithStore(browserHistory, store)

ReactDOM.render(
  <Provider store={store}>
    { /* Tell the Router to use our enhanced history */ }
    <Router history={history}>
      <Route path="/" component={App}>
        <Route path="foo" component={Foo}/>
        <Route path="bar" component={Bar}/>
      </Route>
    </Router>
  </Provider>,
  document.getElementById('mount')
)

Now any time you navigate, which can come from pressing browser buttons or navigating in your application code, the enhanced history will first pass the new location through the Redux store and then on to React Router to update the component tree. If you time travel, it will also pass the new state to React Router to update the component tree again.

How do I watch for navigation events, such as for analytics?

Simply listen to the enhanced history via history.listen. This takes in a function that will receive a location any time the store updates. This includes any time travel activity performed on the store.

const history = syncHistoryWithStore(browserHistory, store)

history.listen(location => analyticsService.track(location.pathname))

For other kinds of events in your system, you can use middleware on your Redux store like normal to watch any action that is dispatched to the store.

What if I use Immutable.js or another state wrapper with my Redux store?

When using a wrapper for your store's state, such as Immutable.js, you will need to change two things from the standard setup:

  1. By default, the library expects to find the history state at state.routing. If your wrapper prevents accessing properties directly, or you want to put the routing state elsewhere, pass a selector function to access the historystate via the selectLocationState option on syncHistoryWithStore.
  2. Provide your own reducer function that will receive actions of type LOCATION_CHANGE and return the payload merged into the locationBeforeTransitions property of the routing state. For example, state.set("routing", {locationBeforeTransitions: action.payload}).

These two hooks will allow you to store the state that this library uses in whatever format or wrapper you would like.

How do I access router state in a container component?

React Router provides route information via a route component's props. This makes it easy to access them from a container component. When using react-redux to connect() your components to state, you can access the router's props from the 2nd argument of mapStateToProps:

function mapStateToProps(state, ownProps) {
  return {
    id: ownProps.params.id,
    filter: ownProps.location.query.filter
  };
}

You should not read the location state directly from the Redux store. This is because React Router operates asynchronously (to handle things such as dynamically-loaded components) and your component tree may not yet be updated in sync with your Redux state. You should rely on the props passed by React Router, as they are only updated after it has processed all asynchronous code.

What if I want to issue navigation events via Redux actions?

React Router provides singleton versions of history (browserHistory and hashHistory) that you can import and use from anywhere in your application. However, if you prefer Redux style actions, the library also provides a set of action creators and a middleware to capture them and redirect them to your history instance.

import { createStore, combineReducers, applyMiddleware } from 'redux';
import { routerMiddleware, push } from 'react-router-redux'

// Apply the middleware to the store
const middleware = routerMiddleware(browserHistory)
const store = createStore(
  reducers,
  applyMiddleware(middleware)
)

// Dispatch from anywhere like normal.
store.dispatch(push('/foo'))

Examples

Examples from the community:

Have an example to add? Send us a PR!

API

routerReducer()

You must add this reducer to your store for syncing to work.

A reducer function that stores location updates from history. If you use combineReducers, it should be nested under the routing key.

history = syncHistoryWithStore(history, store, [options])

Creates an enhanced history from the provided history. This history changes history.listen to pass all location updates through the provided store first. This ensures if the store is updated either from a navigation event or from a time travel action, such as a replay, the listeners of the enhanced history will stay in sync.

You must provide the enhanced history to your <Router> component. This ensures your routes stay in sync with your location and your store at the same time.

The options object takes in the following optional keys:

  • selectLocationState - (default state => state.routing) A selector function to obtain the history state from your store. Useful when not using the provided routerReducer to store history state. Allows you to use wrappers, such as Immutable.js.
  • adjustUrlOnReplay - (default true) When false, the URL will not be kept in sync during time travel. This is useful when using persistState from Redux DevTools and not wanting to maintain the URL state when restoring state.

push(location), replace(location), go(number), goBack(), goForward()

You must install routerMiddleware for these action creators to work.

Action creators that correspond with the history methods of the same name. For reference they are defined as follows:

  • push - Pushes a new location to history, becoming the current location.
  • replace - Replaces the current location in history.
  • go - Moves backwards or forwards a relative number of locations in history.
  • goForward - Moves forward one location. Equivalent to go(1)
  • goBack - Moves backwards one location. Equivalent to go(-1)

Both push and replace take in a location descriptor, which can be an object describing the URL or a plain string URL.

These action creators are also available in one single object as routerActions, which can be used as a convenience when using Redux's bindActionCreators().

routerMiddleware(history)

A middleware you can apply to your Redux store to capture dispatched actions created by the action creators. It will redirect those actions to the provided history instance.

LOCATION_CHANGE

An action type that you can listen for in your reducers to be notified of route updates. Fires after any changes to history.

NPM DownloadsLast 30 Days