react router v6 在组件之外导航

IT技术 javascript reactjs react-router react-router-dom
2021-04-03 22:18:07

在 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以在我的商店中使用它。有什么替代方法吗?

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 (
    <Router
      {...props}
      location={state.location}
      navigationType={state.action}
      navigator={history}
    />
  );
};

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

从这里,你在换CustomRouter用定制的history对象为现有的Router进口react-router-dom

export default function App() {
  return (
    <CustomRouter  history={history}>
      <div className="App">
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/profile" element={<Profile />} />
        </Routes>
      </div>
    </CustomRouter>
  );
}

分叉你的代码和盒子:

编辑 react-router-v6-navigate-outside-of-components

只要改变history={history}navigator={history}并添加location={history.location}

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

function App() {
  return (
    <Router location={history.location} navigator={history}>
      ... my routes
    </Router>
  );
}

export default App;
@kofyohugna 这是使用低级路由器所需的更改,您至少需要在其中指定这些道具。您非常清楚地提到从您的商店访问,您所做的事情比您分享的要多。请将所有相关代码添加到您的问题中。
2021-05-22 22:18:07
@kofyohugna 感谢您使用沙箱,非常感谢。也就是说,不幸的是,看起来 v6不再直接公开历史对象,而且他们似乎没有任何打算这样做。
2021-06-07 22:18:07
@DrewReese 我举了两个例子:首先是反应路由器v5-codeandbox.io/s/great-fire-cxmgh?file=/src/store.js(它工作正常)第二-v6-codeandbox.io/s/weathered -sunset-6mfss?file=/src/App.js(不起作用)
2021-06-11 22:18:07
它不工作。history.push('/')将 url 更改为localhost:3000但页面上的内容不更新
2021-06-12 22:18:07