【问题标题】:Redirect to Route from Saga using React Router v6使用 React Router v6 从 Saga 重定向到路由
【发布时间】:2022-12-30 10:44:46
【问题描述】:

我正在使用 redux saga 和 react router v6,我想从我的一个 sagas 重定向到一条路线,有没有办法做到这一点?

【问题讨论】:

  • 是的,您需要创建一个自定义路由器和历史对象来执行此操作。您能否更新您的问题以包含您的代码的 minimal, complete, and reproducible code example 以及您首先尝试自己执行此操作的任何尝试?
  • 自定义路由器是什么意思?我需要的是从我的传奇功能中重定向到一条路线。在以前的 React 版本中,您可以使用 connected-react-router 库创建 yield put(push(ROUTE)),但它不支持 react router @dre 的 v6
  • 正确的。我的意思是,您使用低级 Router 实现自定义路由器以提供自定义历史记录对象。然后,您可以根据需要在路由器/反应代码之外的其他地方使用此历史记录对象。如果需要,创建自定义异步导航操作。我的回答 here 可能对路由器部分有帮助,将历史对象拉入以发出命令式导航是剩下要做的。

标签: reactjs react-router redux-saga


【解决方案1】:

有多种选择


1 - 将导航方法作为已分派的 redux 操作的一部分发送

// component
const navigate = useNavigate()
dispatch({type: FOO, navigate})

// saga
yield takeEvery(FOO, function*(action) {
  action.navigate('/foo')
})

优点:

  • 您正在使用 react-router 团队推荐的 navigate 方法
  • API 不太可能改变

缺点

  • 您只能在收到此类操作的特定传奇中访问导航方法
  • 您的操作中有不可序列化的数据

2 - 另一种选择是以某种方式存储 navigate 方法。例如。您可以创建一个虚拟反应组件,它将通过 useNavigate 挂钩获取导航方法,然后将其存储在某个“全局”变量中。请参阅此 SO 答案以获取可能的解决方案: https://stackoverflow.com/a/70002872/2347716

这解决了以前解决方案的缺点,但仍然存在一些问题:

  • 在访问导航方法之前,您需要至少渲染一次 React 树
  • 您正在通过引入虚拟组件向视图层添加非视图复杂性

3 - 还有另一种解决方案,类似于我们对 react-router 5 的解决方案,它处理了先前解决方案中的问题。它是使用history对象。它没有记录,因为它不稳定,但是有一个 HistoryRouter 实现作为 react-router-dom 包的一部分。见https://github.com/remix-run/react-router/releases/tag/v6.1.1

import {unstable_HistoryRouter as HistoryRouter} from 'react-router-dom'
import { createBrowserHistory } from "history";
const history = createBrowserHistory()

// saga setup
sagaMiddleware.runSaga(rootSaga, history);

// react
<HistoryRouter history={history} />

这个解决方案的问题是它不稳定,因为它可能与某些 React 18 功能有关。就我个人而言,我更喜欢它,因为它解决了所有其他问题,并且一旦 React 18 实际发布并且我们知道它们是什么,我们就可以处理它。

【讨论】:

  • 谢谢 !我采用了方法 1
  • 请注意,#1 仅在您直接从组件调用操作时才有效 - 而不是另一个传奇。
  • @David,您知道在通过多个 sagas 传递导航功能时让#1 工作的方法吗?即,该组件使用 navigate 分派一个动作,但随后该 saga 调用另一个 saga,也向下传递相同的 navigate。
  • @Aerophite 只需将其作为参数传递:yield call(anotherSaga, navigate) -> function* anotherSaga(navigate){ ... }
  • 第三种解决方案对我不起作用。
【解决方案2】:

我的解决方案

// "HistoryRouter" implementation
import * as React from 'react'
import type {BrowserHistory} from 'history'
import {Router} from 'react-router-dom'

export interface HistoryRouterProps {
    history: BrowserHistory
    basename?: string
    children?: React.ReactNode
}

export function HistoryRouter({
    basename,
    children,
    history,
}: HistoryRouterProps) {
let [state, setState] = React.useState({
    action: history.action,
    location: history.location,
})

React.useLayoutEffect(() => history.listen(setState), [history])

return (
    <Router
         basename={basename}
         children={children}
         location={state.location}
         navigationType={state.action}
         navigator={history}
   />
)
}


// Use
import {createBrowserHistory} from 'history'
export const history = createBrowserHistory()

ReactDOM.render(
   <HistoryRouter history={history}>
       <Routes>
           <Route path="login" element={<LoginComponent />} />
           <Route path="register" element={<RegisterComponent />} />
           <Route path="*" element={<HomeComponent />} />
      </Routes>
   </HistoryRouter>
, root)

// call history push in file saga
function* fetchLoginSaga(action: FetchLoginRequest) {
    try {
         yield call(history.push, "/home")
    } catch (e: any) {
    
    }
}

【讨论】:

  • OP 正在寻找适用于redux-saga 的解决方案。
【解决方案3】:

您可以使用@lagunovsky/redux-react-router 而不是连接的反应路由器因为它支持 react router v6 ve

【讨论】:

    猜你喜欢
    • 2021-12-30
    • 1970-01-01
    • 2022-07-09
    • 2022-06-24
    • 1970-01-01
    • 1970-01-01
    • 2021-07-24
    • 1970-01-01
    相关资源
    最近更新 更多