简体   繁体   English

如何在 react-router-dom v6 中监听路由变化

[英]how to listen for route change in react-router-dom v6

am trying to migrate the old react router dom code to v6 and I want to know how to listen for route change, I am now using useHistory我正在尝试将旧的 React 路由器 dom 代码迁移到 v6,我想知道如何监听路由更改,我现在正在使用useHistory

const history = useHistory()
//then
history.listen(...)

I did read the new docs and I did find that useHistory was changed to useNavigate我确实阅读了新文档,并且确实发现useHistory已更改为useNavigate

const navigate = useNavigate()
//then
navigate.listen(...) // listen is not a function

can you please help me find a way to listen to the route change in v6你能帮我找到一种方法来监听 v6 中的路由变化吗

// This is a React Router v6 app
import { useNavigate } from "react-router-dom";

function App() {
  let navigate = useNavigate();
  function handleClick() {
    navigate("/home");
  }
  return (
    <div>
      <button onClick={handleClick}>go home</button>
    </div>
  );
}

From documentation ( https://reactrouter.com/docs/en/v6/hooks/use-location ), use this hook从文档( https://reactrouter.com/docs/en/v6/hooks/use-location ),使用这个钩子

let location = useLocation();

React.useEffect(() => {
  ga('send', 'pageview');
}, [location]);

The navigate function is a function, not an object like the older react-router-dom version 5's history object. DC navigate function 是 function,而不是像旧的react-router-dom版本 5 的history object 那样的 object。

You can still create a custom history object but you'll need to create a custom router to use it.您仍然可以创建自定义history object,但您需要创建自定义路由器才能使用它。 This allows you to import your history object and create listeners.这允许您导入您的history object 并创建侦听器。

Create a custom router example, use one of the higher-level routers as an example for how they manage the location and state, ie BrowserRouter :创建一个自定义路由器示例,使用其中一个更高级别的路由器作为示例,说明它们如何管理位置和 state,即BrowserRouter

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}
    />
  );
};

In your code create the custom history object for use by your new custom router and other components.在您的代码中创建自定义history object 以供您的新自定义路由器和其他组件使用。

const history = createBrowserHistory();
export default history;

Use your router and pass your history object to it.使用您的路由器并将您的历史记录 object 传递给它。

import CustomRouter from '../CustomRouter';
import history from '../myHistory';

...

<CustomRouter history={history}>
  ....
</CustomRouter>

In a component you want to listen to location changes on, import your history object and invoke the listen callback as you did previously.在您想要监听位置变化的组件中,导入您的历史记录 object 并像之前一样调用listen回调。

import history from '../myHistory';

...

useEffect(() => {
  const unlisten = history.listen((location, action) => {
    // ... logic
  });

  return unlisten;
}, []);

If you want, you may be able to also create your own custom useHistory hook that simply returns your history object.如果您愿意,您还可以创建自己的自定义useHistory挂钩,它只返回您的历史 object。

To add to the accepted answer (can't comment, not enough rep points), subscribing to the history through a useEffect with location.pathname in the dependency array won't work if the navigation unmounts the component you're attempting to call the useEffect from.要添加到已接受的答案(无法评论,没有足够的代表点),如果导航卸载您尝试调用的组件,则通过 useEffect 在依赖项数组中使用 location.pathname 订阅历史记录将不起作用使用效果来自。

If you need to react to a change in the route due to back button specifically:如果您需要对由于后退按钮引起的路线变化做出具体反应:

In react-router-dom v6.8.0 or even earlier, trying to attach a listener to the history , will throw an error: A history only accepts one active listener .react-router-dom v6.8.0或更早版本中,尝试将监听器附加到history中,将抛出错误: A history only accepts one active listener

I learnt that react-router-dom seems to introduce a lot of changes between the minor versions as well, so you should take words like unsafe and unstable, like in unstable_HistoryRouter especially serious.我了解到react-router-dom似乎也在次要版本之间引入了很多变化,所以你应该特别认真地对待不安全和不稳定的词,比如unstable_HistoryRouter They will break sooner or later, if you're not very lucky.如果你运气不好,它们迟早会坏掉。

In my case I had to upgrade to get the reintroduced optional route params, and the UNSAFE_NavigationContext my former colleague decided to use, didn't work anymore.在我的例子中,我必须升级才能获得重新引入的可选路由参数,而我的前同事决定使用的UNSAFE_NavigationContext不再起作用。

So here's a high level approach, that allows you to listen to the actions on the Router's history stack, without attaching another listener to the router yourself .所以这是一个高级方法,它允许您监听路由器历史堆栈上的操作而无需自己将另一个监听器附加到路由器 Which is fine, as it already has one listener by default, and it's just not exposed, but the actions derived from it are, which is enough.这很好,因为默认情况下它已经有一个侦听器,只是没有公开,但是从中派生的操作是足够的。

In the following example we are reacting to changes in location and for each change, we check if it was due to a POP action, thats eg triggered when the browser's back button is used, and then execute whatever..在下面的示例中,我们对location的变化做出反应,对于每个变化,我们检查它是否是由于POP操作引起的,例如,当使用浏览器的后退按钮时触发,然后执行任何...

import { useEffect } from "react";
import {
  Location,
  NavigationType,
  useLocation,
  useNavigationType,
} from "react-router-dom";

export const useBackListener = (callback: () => void) => {
  const location: Location = useLocation();
  const navType: NavigationType = useNavigationType();

  useEffect(() => {
    if (navType === "POP" && location.key !== "default") {
      if (someCondition === true) callback();
      else {
        doSomethingElse();
      }
    }
  }, [location]);
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM