redux-first-history vs connected-react-router vs react-router vs react-router-redux vs redux-logger
React 路由和状态管理库
redux-first-historyconnected-react-routerreact-routerreact-router-reduxredux-logger类似的npm包:

React 路由和状态管理库

这些库主要用于处理 React 应用中的路由和状态管理。它们提供了不同的功能和设计理念,以帮助开发者在构建复杂的单页应用时更好地管理路由和状态。通过这些库,开发者可以实现更流畅的用户体验,并提高应用的可维护性和可扩展性。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
redux-first-history91,35345399.3 kB152 年前MIT
connected-react-router04,699444 kB176-MIT
react-router056,2854.18 MB15312 天前MIT
react-router-redux07,768-19 年前MIT
redux-logger05,734-589 年前MIT

功能对比: redux-first-history vs connected-react-router vs react-router vs react-router-redux vs redux-logger

路由管理

  • redux-first-history:

    redux-first-history 通过 Redux 管理历史记录,允许在路由变化时触发 Redux action,适合需要精细控制路由的应用。

  • connected-react-router:

    connected-react-router 允许你将 React Router 的路由状态与 Redux 状态同步,使得路由变化能够通过 Redux action 进行管理,适合需要复杂路由逻辑的应用。

  • react-router:

    react-router 是一个灵活且强大的路由库,支持动态路由、嵌套路由等功能,适合各种规模的应用。

  • react-router-redux:

    react-router-redux 旨在将 React Router 的路由状态与 Redux 结合,但由于不再维护,建议使用其他解决方案。

  • redux-logger:

    redux-logger 是一个中间件,用于在控制台中记录 Redux 状态的变化,帮助开发者调试和跟踪状态变化。

状态管理

  • redux-first-history:

    redux-first-history 允许在 Redux 中直接管理历史记录,适合需要在状态管理中包含路由信息的应用。

  • connected-react-router:

    通过与 Redux 的结合,connected-react-router 使得路由状态可以作为 Redux store 的一部分进行管理,便于在应用中共享和访问路由信息。

  • react-router:

    react-router 本身不提供状态管理功能,通常与其他状态管理库(如 Redux)结合使用,以实现更复杂的状态管理。

  • react-router-redux:

    react-router-redux 通过将路由状态映射到 Redux store,提供了一种将路由状态与应用状态结合的方式,但已不再维护。

  • redux-logger:

    redux-logger 主要用于调试,不涉及状态管理,但可以帮助开发者理解状态变化的过程。

学习曲线

  • redux-first-history:

    redux-first-history 需要开发者对 Redux 有一定的理解,学习曲线适中,适合希望在 Redux 中管理路由的开发者。

  • connected-react-router:

    connected-react-router 的学习曲线相对较陡,需要理解 Redux 和 React Router 的结合使用,适合有一定经验的开发者。

  • react-router:

    react-router 的学习曲线较平缓,文档丰富,易于上手,适合新手和有经验的开发者。

  • react-router-redux:

    由于不再维护,react-router-redux 的学习曲线可能会让新手感到困惑,建议使用更现代的替代方案。

  • redux-logger:

    redux-logger 的学习曲线非常平缓,易于使用,适合所有级别的开发者。

维护状态

  • redux-first-history:

    redux-first-history 仍在维护中,适合需要在 Redux 中管理历史记录的项目。

  • connected-react-router:

    connected-react-router 仍在维护中,适合需要与 Redux 结合使用的项目,确保路由状态的可靠管理。

  • react-router:

    react-router 是一个成熟且活跃的项目,持续更新和维护,适合各种类型的应用。

  • react-router-redux:

    react-router-redux 已不再维护,建议寻找其他解决方案以避免潜在问题。

  • redux-logger:

    redux-logger 作为调试工具,仍然活跃并得到维护,适合需要调试 Redux 状态的开发者。

扩展性

  • redux-first-history:

    redux-first-history 允许开发者自定义历史记录管理,适合需要特定路由行为的应用。

  • connected-react-router:

    connected-react-router 提供了与 Redux 的良好集成,便于扩展和定制路由行为,适合需要复杂路由逻辑的应用。

  • react-router:

    react-router 具有高度的扩展性,支持自定义路由组件和中间件,适合各种需求的应用。

  • react-router-redux:

    react-router-redux 的扩展性有限,因其已不再维护,建议使用其他解决方案。

  • redux-logger:

    redux-logger 可以与其他中间件结合使用,提供灵活的调试选项,适合需要详细状态跟踪的开发者。

如何选择: redux-first-history vs connected-react-router vs react-router vs react-router-redux vs redux-logger

  • redux-first-history:

    选择 redux-first-history 如果你想在 Redux 中管理历史记录,且希望在路由变化时触发 Redux action,适合需要精细控制路由行为的应用。

  • connected-react-router:

    选择 connected-react-router 如果你需要将 React Router 与 Redux 状态管理结合使用,以便在 Redux 中同步路由状态,适合需要复杂路由管理的应用。

  • react-router:

    选择 react-router 如果你只需要一个强大且灵活的路由解决方案,适合中小型应用,且不需要与 Redux 结合。

  • react-router-redux:

    选择 react-router-redux 如果你希望将 React Router 的路由状态与 Redux 状态管理结合,但需要注意该库已不再维护,建议使用其他替代方案。

  • redux-logger:

    选择 redux-logger 如果你需要在开发过程中调试 Redux 状态变化,适合希望实时查看状态变化的开发者。

redux-first-history的README

redux-first-history


Redux First History - Make Redux 100% SINGLE-AND-ONLY source of truth!

Redux history binding for

Compatible with immer - redux-immer - redux-immutable.

:tada: A smaller, faster, optionated, issue-free alternative to connected-react-router

Table of Contents

Main Goal

While working with relatively large projects, it's quite common to use both redux and react-router.

So you may have components that take location from the redux store, others that take location from router context, and others from withRouter HOC.

This can generate sync issues, due to the fact that many components are updated at different times. In addition, React shallowCompare rendering optimization will not work as it should.

With redux-first-history, you can mix components that get history from wherever, they will always be tunneled to state.router.location !

Use whatever you like. History will just work as it should.

//react-router v5 - v6
useLocation() === state.router.location

//react-router v5
this.props.history.location === state.router.location
this.props.location === state.router.location
withRouter.props.location === state.router.location

//react-router v4
this.context.router.history.location === state.router.location
this.context.route.location === state.router.location

//@reach/router
this.props.location === state.router.location

//wouter - pathname
useLocation()[0] === state.router.location.pathname

Mix redux, redux-saga, react-router, @reach/router, wouter and react-location without any synchronization issue!
Why? Because there is no synchronization at all! There is only one history: reduxHistory!

  • One way data-flow
  • One unique source of truth
  • No more location issues!

Edit Redux-First Router Demo

Demo

Main Features

  • 100% one source of truth (store)
  • No synchronization depending on rendering lifecycle (ConnectedRouter)
  • No React dependency (we want history to be always in store!)
  • 100% one-way data flow (only dispatch actions!)
  • Improve React shallowCompare as there is only one "location"
  • Support react-location 3.x
  • Support react-router v4 / v5 / v6
  • Support @reach/router 1.x
  • Support wouter 2.x
  • Support mix react-router, @reach/router & wouter in the same app!
  • Fast migration from an existing project, with the same LOCATION_CHANGE and push actions (taken from RRR)
  • Handle Redux Travelling from dev tools (that's nonsense in production, but at the end of the day this decision it's up to you ...)

Installation

Using npm:

$ npm install --save redux-first-history

Or yarn:

$ yarn add redux-first-history

Usage

store.js

import { createStore, combineReducers, applyMiddleware } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import { createReduxHistoryContext, reachify } from "redux-first-history";
import { createWouterHook } from "redux-first-history/wouter";
import { createBrowserHistory } from 'history';

const { createReduxHistory, routerMiddleware, routerReducer } = createReduxHistoryContext({ 
  history: createBrowserHistory(),
  //other options if needed 
});

export const store = createStore(
  combineReducers({
    router: routerReducer
    //... reducers //your reducers!
  }),
  composeWithDevTools(
    applyMiddleware(routerMiddleware)
  )
);

export const history = createReduxHistory(store);
//if you use @reach/router 
export const reachHistory = reachify(history);
//if you use wouter
export const wouterUseLocation = createWouterHook(history);

store.js (with @reduxjs/toolkit)

import { combineReducers } from "redux";
import { configureStore } from "@reduxjs/toolkit";
import { createReduxHistoryContext } from "redux-first-history";
import { createBrowserHistory } from "history";

const {
  createReduxHistory,
  routerMiddleware,
  routerReducer
} = createReduxHistoryContext({ history: createBrowserHistory() });

export const store = configureStore({
  reducer: combineReducers({
    router: routerReducer
  }),
  middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(routerMiddleware),
});

export const history = createReduxHistory(store);

app.js

import React, { Component } from "react";
import { Provider, connect } from "react-redux";
import { Router } from "react-router-dom";
import { store, history } from "./store";

const App = () => (
      <Provider store={store}>
        <Router history={history}>
        //.....
        </Router>
      </Provider>
    );

export default App;

app.js (react-router v6)

import React, { Component } from "react";
import { Provider } from "react-redux";
import { HistoryRouter as Router } from "redux-first-history/rr6";
import { store, history } from "./store";

const App = () => (
      <Provider store={store}>
        <Router history={history}>
        //.....
        </Router>
      </Provider>
    );

export default App;

saga.js (react-saga)

import { put } from "redux-saga/effects";
import { push } from "redux-first-history";

function* randomFunction() {
  //....
  yield put(push(YOUR_ROUTE_PATH));
  //....
}

slice.js (in a Thunk with @reduxjs/toolkit)

import { push } from "redux-first-history";

export const RandomThunk = (dispatch) => {
  //....
  dispatch(push(YOUR_ROUTE_PATH));
  //....
}
  • Just a simple Router with no more ConnectedRouter!
  • Probably, you already did connect the Redux store with react-router-redux or connected-react-router (in this case you have only to replace the import!)

Options

export const createReduxHistoryContext = ({
  history, 
  routerReducerKey = 'router', 
  reduxTravelling = false, 
  selectRouterState = null,
  savePreviousLocations = 0,
  batch = null,
  reachGlobalHistory = null
})
keyoptionaldescription
historynoThe createBrowserHistory object - v4.x/v5.x
routerReducerKeyyesif you don't like router name for reducer.
reduxTravellingyesif you want to play with redux-dev-tools :D.
selectRouterStateyescustom selector for router state. With redux-immutable selectRouterState = state => state.get("router")
savePreviousLocationsyesif > 0 add the key "previousLocation" to state.router, with the last N locations. [{location,action}, ...]
batchyesa batch function for batching states updates with history updates. Prevent top-down updates on react : usage import { unstable_batchedUpdates } from 'react-dom'; batch = unstable_batchedUpdates
reachGlobalHistoryyesglobalHistory object from @reach/router - support imperatively navigate of @reach/router - import { navigate } from '@reach/router' : usage import { globalHistory } from '@reach/router'; reachGlobalHistory = globalHistory
basenamenosupport basename (history v5 fix)

Advanced Config

  • Support "navigate" from @reach/router
import { createReduxHistoryContext, reachify } from "redux-first-history";
import { createBrowserHistory } from 'history';
import { globalHistory } from '@reach/router';

const { createReduxHistory, routerMiddleware, routerReducer } = createReduxHistoryContext({ 
  history: createBrowserHistory(),
  reachGlobalHistory: globalHistory,
  //other options if needed 
});
  • React batch updates: top-down batch updates for maximum performance. Fix also some updated edge cases.
import { createReduxHistoryContext, reachify } from "redux-first-history";
import { createBrowserHistory } from 'history';
import { unstable_batchedUpdates } from 'react-dom';

const { createReduxHistory, routerMiddleware, routerReducer } = createReduxHistoryContext({ 
  history: createBrowserHistory(),
  batch: unstable_batchedUpdates,
  //other options if needed 
});

Feedback

Let me know what do you think!
Enjoy it? Star this project! :D

Credits & Inspiration

  • redux-first-routing
  • react-router-redux
  • connected-react-router

Contributors

See Contributors.

License

MIT License.