【问题标题】:React redux is not changing routesReact redux 没有改变路由
【发布时间】:2018-11-18 04:54:11
【问题描述】:

更新此问题以使用connected-react-router 而不是react-router-redux,因为它与react-router v4 不兼容。

调度操作时,我的路由似乎无法正常工作。我怀疑这是因为我使用的 sagas 配置不正确。

我有一个传奇:

import { call } from 'redux-saga/effects'
import { push } from 'connected-react-router'

//...

yield call(push, '/dashboard')

尽管 webdev 工具中的 redux 日志显示操作已成功调度,但推送功能不会将浏览器重定向到指定路径。

顶级 index.js 文件如下所示:

import createSagaMiddleware from 'redux-saga'
import rootSaga from './redux/sagas'
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import logger from 'redux-logger'
import App from './App'
import registerServiceWorker from './registerServiceWorker'
import rootReducer from './redux/modules'
import { applyMiddleware, compose, createStore } from 'redux'
import { createBrowserHistory } from 'history'
import { routerMiddleware, connectRouter } from 'connected-react-router'

const history = createBrowserHistory()
const sagaMiddleware = createSagaMiddleware()
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(
  connectRouter(history)(rootReducer),
  composeEnhancer(
    applyMiddleware(
      sagaMiddleware,
      routerMiddleware(history),
      logger
    )
  )
)

sagaMiddleware.run(rootSaga)

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

render()

registerServiceWorker()

包含根组件的 App.js 文件有:

import { ConnectedRouter } from 'connected-react-router'
import { Route, Switch, Redirect } from 'react-router-dom'

const App = ({ history }) => {
  return (
    <ConnectedRouter history={history}>
      <Switch>
        { routes }
      </Switch>
    </ConnectedRouter>
  )
}

export default App

此设置中缺少什么以使其正常工作?

依赖版本:

"react-redux": "^5.0.7",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
"connected-react-router": "^4.3.0"

【问题讨论】:

  • 请注意,react-router-redux@5.0.0-alphaXX 可与 react-router@4.X.X 正常工作
  • @Simpleton 我发布了我的解决方案。不知道它是否正确,但似乎对我有用。你找到其他解决方案了吗?

标签: reactjs redux react-router react-router-v4


【解决方案1】:

historypush 方法(这是一个不纯函数)不同,connected-react-routerpush 是一个动作创建者及其结果(action) 必须被调度以触发导航。
要在redux-saga 中这样做,您必须使用put,而不是call

call 创建一个通话效果
当产生时,它只是执行给定参数的给定函数并返回结果。通过将我们与函数的直接执行解耦,它非常适合(但不限于)不纯函数调用(例如网络请求)。

put 创建一个调度效果
当产生时,它分派传入的动作对象。因此,仅将您的代码与dispatch 的直接调用分离,而不是动作创建者(这应该是纯粹的设计)。

因此,在您的情况下,解决方案如下所示:

yield put(push('/dashboard'))

P.S:同样适用于react-router-reduxpush

【讨论】:

    【解决方案2】:

    您需要连接router's middleware,例如:

    import { browserHistory } from 'react-router'
    import { routerMiddleware } from 'react-router-redux'
    
    const sagaMw = createSagaMiddleware()
    const routerMw = routerMiddleware(browserHistory)
    const middleware = applyMiddleware(sagaMw, routerMw, logger)
    

    【讨论】:

    • 此配置仅适用于 react-router v3。对于版本 4(如上所示),该导入导致 'react-router' does not contain an export named 'browserHistory'
    • 您的评论让我注意到 react-router-redux 没有得到维护并且与 react-router 4 不兼容,因此我更新了问题的详细信息。
    • 在没有 Redux 的情况下直接调用 push('/dashboard') 自己工作,例如在一些虚拟按钮的点击处理程序中?和/或当您调度其他一些功能时,它是否被执行,例如yield call(console.log, 'test')?如果两者都单独工作,您可以尝试使用不同顺序的中间件,如果这不起作用并且没有其他人可以解决,我建议使用redux-thunk 而不是 sagas¯\_(ツ)_/¯
    • 应该在应用初始化期间注入历史对象,所以createStore = (state, history) =&gt; {...}。因此,将此文件与特定的历史对象类型解耦。
    • 嘿,我正在使用 react-router-reduxreact-router v4 并且效果非常好。它说它是 alpha 版,但它在我的项目中完美运行:github.com/ReactTraining/react-router/tree/master/packages/…
    【解决方案3】:

    Sagas 被实现为生成器函数,它们向 redux-saga 中间件

    所以你的 Saga 应该导出一个 Generator 函数:

    import { call } from 'redux-saga/effects'
    import { push } from 'connected-react-router'
    
    //...
    
    export function* rootSaga() {
        return yield call(push, '/dashboard')
    }
    

    rootSaga 应该用sagaMiddleware 注册:

    import { rootSaga } from './redux/sagas';
    ...
    sagaMiddleware.run(rootSaga)
    ...
    

    参考:https://redux-saga.js.org/docs/introduction/BeginnerTutorial.html

    【讨论】:

      【解决方案4】:

      似乎对我有用的是使用withRoter(不知道它是否正确):

      export default withRouter(compose(withConnect)(App)); //wrapped in withRouter
      

      或者

      export default compose(
        withRouter,
        withConnect,
      )(App);
      

      在 redux-saga 中:

      yield put(push('/newpage'));
      

      我使用 react-boilerplate,https://github.com/react-boilerplate/react-boilerplate。 我不知道它是否正确,但是这样路由在 url 中发生了变化,我到达了新的路由。如果我不使用withRouter,则 url 中的路由会发生变化,并且不会再发生任何事情...... 我在这里找到了解决方案https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/withRouter.md

      希望有人对此发表意见。 https://github.com/react-boilerplate/react-boilerplate 的人可能吗?

      【讨论】:

        猜你喜欢
        • 2018-07-01
        • 2017-05-09
        • 1970-01-01
        • 2020-08-13
        • 2018-04-27
        • 2018-02-14
        • 2017-12-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多