我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

React Router@v5之后的版本,取消了useHistory()这个钩子。在ReactRouter@v6版本中,其有关导航的部分功能,使用新的钩子useNavigate()代替。而history.listen()这部分功能,在新版本的react router中该如何实现呢?这就是本文要讨论的内容。

苏南大叔:React路由,使用useLocation()和useEffect()实现路由监控 - react路由监控
React路由,使用useLocation()和useEffect()实现路由监控(图2-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0create-react-app@5.0.1react-router-dom@6.27.0react@18.3.1

旧版history.listen()主要功能

history.listen()老版本的代码,这里苏南大叔就不列举了。看名字也能猜出相关功能来,就是对react程序的浏览历史的监控功能,或者说是location的变化情况。

当然,这里需要特别强调的是:并不是浏览器的历史记录功能,两者还是有比较大的区别的。reactlocation并不等同于windowlocation

新的实现方案

在新的版本中,实际上可以使用useLocation() + useEffect(),组合获得历史记录。核心组合如下:

import React, { useEffect } from "react";
import { useLocation } from "react-router-dom";
const location = useLocation();
useEffect(() => {
  console.log(location);
  //...
}, [location]);

参考文章:

浏览历史组件

苏南大叔这里实现了一个组件,实现的主要功能就是对location的监控。可以用于对路由相关功能的调试,比如<Link to=''>等功能的记录等。

主要代码如下:

import React, { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";

function HistoryBar() {
  const location = useLocation();
  const [historyRecords, setHistoryRecords] = useState([]);
  useEffect(() => {
    if (location.state === null || location.state === "null") {
      location.state = "";
    }
    setHistoryRecords([location].concat(historyRecords));
  }, [location]);
  return (
    <div>
      <table>
        <tbody>
          {historyRecords.map((record, index) => (
            <tr key={index}>
              <td>{record.key}</td>
              <td>{record.pathname}</td>
              <td>{record.search}</td>
              <td>{JSON.stringify(record.state, "", 2)}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}
export default HistoryBar;

苏南大叔:React路由,使用useLocation()和useEffect()实现路由监控 - history
React路由,使用useLocation()和useEffect()实现路由监控(图2-2)

调用举例:

import { NavLink, Outlet } from "react-router-dom";
import HistoryBar from "./HistoryBar";
const Layout = () => {
  return (
    <>
      <div className="bar">
        <NavLink to="/" state={{ id: 1, title: "首页" }}>
          首页
        </NavLink>
        <NavLink to="/s">S页面</NavLink>
        <NavLink to="/n">N页面</NavLink>
      </div>
      <HistoryBar></HistoryBar>
      <Outlet></Outlet>
    </>
  );
};

当然,本文的重要前提是上述代码,包裹在一个router里面,这个道理大家都明白。这里就不详细描述了,可以参考苏南的相关文章:

可能遇到的问题

eslint对上面的代码,可能会提示信息:

React Hook useEffect has a missing dependency: 'historyRecords'. Either include it or remove the dependency array. You can also do a functional update 'setHistoryRecords(h => ...)' if you only need 'historyRecords' in the 'setHistoryRecords' call

苏南大叔觉得它的提示有道理,但是,从这个组件的设计上来说,数据的驱动并不允许其它地方来主动修改这个值historyRecords。所以,并没有这个依赖需求。

结语

苏南大叔的React相关经验文章,请参考下面的链接:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   react