react router v6 在组件外部导航

新手上路,请多包涵

在 react-router v5 中,我创建了这样的历史对象:

 import { createBrowserHistory } from "history";
export const history = createBrowserHistory();

然后将其传递给路由器:

 import { Router, Switch, Route, Link } from "react-router-dom";
<Router history={history}>
 ... my routes
</Router>

我这样做是为了有机会在组件之外使用历史记录:

    // store action
    logout() {
        this.user = null;
        history.push('/');
    }

通过这种方式,我将逻辑移至商店,并尽可能保持组件干净。但是现在,在 React Router v6 中我不能做同样的事情。我仍然可以在我的组件内使用 useNavigate() 进行导航,但我无法创建 navigate 以将其用于我的商店。还有其他选择吗?

原文由 kofyohugna 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

好吧,事实证明,如果您实现一个以与 RRDv6 路由器相同的方式实例化历史状态的自定义路由器,您 就可以 复制该行为。

例如检查 BrowserRouter 实现:

>  export function BrowserRouter({
>   basename,
>   children,
>   window
> }: BrowserRouterProps) {
>   let historyRef = React.useRef<BrowserHistory>();
>   if (historyRef.current == null) {
>     historyRef.current = createBrowserHistory({ window });
>   }
>
>   let history = historyRef.current;
>   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}
>     />
>   );
> }
>
> ```

创建一个 `CustomRouter` 使用自定义 `history` 对象并管理状态:

const CustomRouter = ({ history, …props }) => { const [state, setState] = useState({ action: history.action, location: history.location });

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

return ( ); };


这有效地将自定义 `history` 对象代理到 `Router` 并管理导航状态。

From here you swap in the `CustomRouter` with custom `history` object for the existing `Router` imported from `react-router-dom` .

export default function App() { return (

} /> } />
); }


你的codesandbox的分支:

[![编辑 react-router-v6-navigate-outside-of-components](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/agitated-euler-90kf3?fontsize=14&hidenavigation=1&module=%2Fsrc%2FApp.js&theme=dark)

## 更新

`react-router-dom@6` 显示历史路由器。

[历史路由器](https://reactrouter.com/docs/en/v6/routers/history-router)

> `<unstable_HistoryRouter>` 将 [`history`](https://github.com/remix-run/history) 库的实例作为道具。这允许您在非 React 上下文中使用该实例或将其用作全局变量。
>
> ```
>  import { unstable_HistoryRouter as HistoryRouter } from "react-router-dom";
> import { createBrowserHistory } from "history";
>
> const history = createBrowserHistory({ window });
>
> ReactDOM.render(
>   <HistoryRouter history={history}>
>     {/* The rest of your app goes here */}
>   </HistoryRouter>,
>   root
> );
>
> ```

有这个注释:

> 此 API 目前的前缀为 `unstable_` 因为您可能无意中将两个版本的 `history` 库添加到您的应用程序,您已添加到 package.json 的版本以及 React Router 使用的任何版本在内部。如果您的工具允许,建议不要将 `history` 添加为直接依赖项,而是依赖于 `react-router` 包中的嵌套依赖项。一旦我们有了检测不匹配版本的机制,此 API 将删除其 `unstable_` 前缀。

## RRDv6.4 注释

如果您使用的是 RRDv6.4 而 _不是_ 使用数据路由器,那么好消息是 `unstable_HistoryRouter` 至少在 RRDv6.4.5 之前仍然有效。您可以 [在此处](https://github.com/remix-run/react-router/issues/9422#issuecomment-1301182219) 关注存储库中已提交的问题。

如果您使用的是数据路由器,那么新的“不稳定”方法是直接使用路由器对象中的附加 `navigate` 函数。

例子:

import { createBrowserRouter } from ‘react-router-dom’;

const router = createBrowserRouter(…);

router.navigate(targetPath, options);

”`

原文由 Drew Reese 发布,翻译遵循 CC BY-SA 4.0 许可协议

已接受答案的 TypeScript 解决方案

历史对象:

 import { createBrowserHistory } from "history";

const customHistory = createBrowserHistory();

export default customHistory;

BrowserRouterProps 是一种 react-router 类型。

>  export interface BrowserRouterProps {
>   basename?: string;
>   children?: React.ReactNode;
>   window?: Window;
> }
>
> ```

自定义路由器:

import { useLayoutEffect, useState } from “react”; import { BrowserRouterProps, Router } from “react-router-dom”; import { BrowserHistory } from “history”; import customHistory from “./history”; interface Props extends BrowserRouterProps { history: BrowserHistory; } export const CustomRouter = ({ basename, history, children }: Props) => { const [state, setState] = useState({ action: history.action, location: history.location, }); useLayoutEffect(() => history.listen(setState), [history]); return ( ); };


使用 CustomRouter 而不是 BrowserRouter

ReactDOM.render( , document.getElementById(“root”) );

”`

原文由 Okan Karadag 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题