react-router-dom 配置路由

参考:

  1. https://www.jianshu.com/p/a0427a55ae47
  2. https://github.com/remix-run/react-router/blob/main/docs/getting-started/tutorial.md
  3. https://serializedowen.github.io/docs/react-router-dom/向导/核心组件
  4. https://reactrouterdotcom.fly.dev/docs/en/v6/getting-started/overview
  5. https://www.jianshu.com/p/d991a4a55ae1
  6. https://www.cnblogs.com/menggirl23/p/10288477.html

0 安装

npm install --save react-router
或者
npm install --save react-router-dom

对比

react-router react-router-dom
关系 不能通过操作dom控制路由 在React-router的基础上扩展了可操作dom的api
区别 包内容较多 比较轻巧
跳转方式对比 3.0以上版本用this.props.router.push('/path')实现跳转,4.0以上版本用this.props.history.push('/path') this.props.history.push('/path')

PS

react-router优点

与React融为一体,专为react量身打造,编码风格与react保持一致,例如路由的配置可以通过component来实现

不需要手工维护路由state,使代码变得简单
强大的路由管理机制,体现在如下方面
路由配置: 可以通过组件、配置对象来进行路由的配置
路由切换: 可以通过 Redirect进行路由的切换
路由加载: 可以同步记载,也可以异步加载,这样就可以实现按需加载
使用方式: 不仅可以在浏览器端的使用,而且可以在服务器端的使用

PS:安装react-router-dom的时候,不需要npm安装react-router。

1 react-router-dom

1.0 v5 升级至 v6 的变化

移除的:

  • 把 Switch 标签替换成了 Routes 标签
  • component 替换成了 element
  • 移除了 Redirect
1.0.0 Switch 不再使用,转而使用更强大的 Routes:
  1. 可以使用相对路径(path开头不是 / 就是相对路由)
  1. 根据最佳匹配选择路由,而不是根据路由的排序。
  1. 路由可以嵌套

PS:
<Routes> 会遍历它的children,生成一个数组。
useRoutes(routesGoHere) 可以实现同样的效果

1.0.1 路径匹配更加精确
<Route path="teams/:teamId" element={<Team />} />
<Route path="teams/new" element={<NewTeamForm />} />

URL /teams/new 都能匹配这两个路由,但是teams/new 更加具体,所以会渲染

1.0.2 useNavigate 实现自定义
import { useNavigate } from "react-router-dom";

function Invoices() {
  let navigate = useNavigate();
  return (
    <div>
      <NewInvoiceForm
        onSubmit={async (event) => {
          let newInvoice = await createInvoice(
            event.target
          );
          navigate(`/invoices/${newInvoice.id}`);
        }}
      />
    </div>
  );
}
1.0.3 useParams()读取路由参数
import { Routes, Route, useParams } from "react-router-dom";

function App() {
  return (
    <Routes>
      <Route
        path="invoices/:invoiceId"
        element={<Invoice />}
      />
    </Routes>
  );
}

function Invoice() {
  let params = useParams();
  return <h1>Invoice {params.invoiceId}</h1>;
}
1.0.4 嵌套式路由
1.0.5 默认子路由

使用场景:有时候url和某个parent路由匹配了,但是没有和这个parent路由的任何子路由匹配,那么这时候就不会渲染任何子组件。
但有时候我们的业务场景是需要默认显示某个子页面的。

解决方法:增加一个含有index属性的子路由,当发生上面的情况的时候自动显示index对应的组件

function App() {
  return (
    <Routes>
      <Route path="/" element={<Layout />}>
        <Route index element={<Activity />} />   //增加这一行
        <Route path="invoices" element={<Invoices />} />
        <Route path="activity" element={<Activity />} />
      </Route>
    </Routes>
  );
}

有时候修改了parent路由的名字,就要对应地修改一大堆路由的名字,包括跳转的时候的url,有了relative link就减少了修改。

<Route path="dashboard" element={<Dashboard />}>
        <Route path="invoices" element={<Invoices />} />
        <Route path="team" element={<Team />} />
      </Route>

function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>
      <nav>
        <Link to="invoices">Invoices</Link>{" "}
        <Link to="team">Team</Link>
      </nav>
      <hr />
      <Outlet />
    </div>
  );
}
1.0.7 在子组件中也能使用Routes

要记得在parent路由里加上'/*'

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="dashboard/*" element={<Dashboard />} />
    </Routes>
  );
}

function Dashboard() {
  return (
    <div>
      <p>Look, more routes!</p>
      <Routes>
        <Route path="/" element={<DashboardGraphs />} />
        <Route path="invoices" element={<InvoiceList />} />
      </Routes>
    </div>
  );
}
1.0.8 Layout路由
 <Route element={<PageLayout />}>
    <Route path="/privacy" element={<Privacy />} />
    <Route path="/tos" element={<Tos />} />
  </Route>

1.1 名词解释

  1. Location :基于window.location对象,用来表示“where the user is at”
{
  pathname: "/bbq/pig-pickins",
  search: "?campaign=instagram",
  hash: "#menu",
  state: null,
  key: "aefz24ie"
}

前三个属性和window.location的属性一样,后两个是React Router独有的。

pathname属性:URL里origin以后的部分(origin包括协议、域名和端口), 比如 https://example.com/teams/hotspurs 的 pathname 是 /teams/hostspurs.

  1. History: 一个对象。它让React Router修改url,提供API来修改浏览器的 history stack
  • 传统网站:用户每次点击前进后退按钮,点击链接,都要向服务器发送请求
  • client side routing:
<a
  href="/contact"
  onClick={(event) => {
    // stop the browser from changing the URL and requesting the new document
    event.preventDefault();
    // push an entry into the browser history stack and change the URL
    window.history.pushState({}, undefined, "/contact");
  }}
/>

这样就可以阻止浏览器向服务器发送请求。

  • 如果想要让UI在URL变化的时候随之改变的话,就要监控URL变化。
    但是window.addEventListener("popstate", () => {}); 只能监控到history.back()或者history.forward()
    如果调用history.pushState()或history.replaceState()不会被监听到。
  • React Router 在 push, pop, or replace的时候,项目就会渲染出对应的UI。
  1. History Action :push/pop/replace

1.1 路由器

  • BrowserRouter 使用 HTML5 提供的 history API ,保证你的 UI 界面和 URL 保持同步。

创造一个 history, puts the initial location in to state, and subscribes to the URL.
history对象修改了url,就会告知 =》 BrowserRouter重新渲染

1.2 导航(navigation)

有两种方法:

  1. <Link>
  2. useNavigate

React Router will prevent the browser's default behavior and tell the history to push a new entry into the history stack. The location changes and the new matches will render.

1.2.1 useNavigate Hook
let navigate = useNavigate();
useEffect(() => {
  setTimeout(() => {
    navigate("/logout");
  }, 30000);
}, []);

1.3 获取数据

let location = useLocation();
let urlParams = useParams();
let [urlSearchParams] = useSearchParams();

1.4 useSearchParams

 let [searchParams, setSearchParams] = useSearchParams();
  1. setSearchParams({filter:123})会把 ?filter=123 插到url后面
  2. 通过<Link to="/shoes?brand=nike">Nike</Link>跳转之后,可以通过searchParams获取search的值,其有下面这些属性:
const handleSearch = () => {
		navigate("/user/2333?type=1");
	};
import { useParams, useSearchParams } from "react-router-dom";

const UserInfo = (props) => {
	const params = useParams();
	const [search] = useSearchParams();
	console.log(search.get("type")); //打印结果为1

	return (
		<div>
			User Info
			<div>The user's index is {params.id}</div>
		</div>
	);
};
export default UserInfo;

2 举例

/src/index.js

import React from "react";
import ReactDOM from "react-dom/client";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
import LayoutPage from "./LayoutPage";
import Users from "./pages/Users";
import UserInfo from "./pages/UserInfo";
import NotFound from "./pages/NotFound";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
	<React.StrictMode>
		<BrowserRouter>
			<Routes>
				<Route element={<LayoutPage></LayoutPage>}>
					<Route path="/" element={<Navigate to="/user" />}></Route>
					<Route path="/user" element={<Users></Users>}></Route>
					<Route path="/user/:id" element={<UserInfo></UserInfo>}></Route>
					<Route path="*" element={<NotFound></NotFound>}></Route>
				</Route>
			</Routes>
		</BrowserRouter>
	</React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

/src/LayoutPage.js

import { Link, Outlet } from "react-router-dom";

const LayoutPage = (props) => {
	return (
		<div style={{ height: "100vh", backgroundColor: "gray", display: "flex" }}>
			{/* 左边一列 */}
			<div
				style={{
					backgroundColor: "black",
					width: "200px",
					height: "100%",
					display: "flex",
					flexDirection: "column",
				}}
			>
				<div style={{ color: "white", height: "48px" }}>Navigation</div>
				<div style={{ backgroundColor: "gray", flex: "1 auto" }}>
					<Link to="user">to user</Link>
				</div>
			</div>

			{/* 右边一列 */}
			<div
				style={{
					backgroundColor: "white",
					flex: "1 auto",
					display: "flex",
					flexDirection: "column",
				}}
			>
				<div
					style={{ height: "48px", backgroundColor: "brown", color: "white" }}
				>
					HEADER
				</div>
				<div style={{ flex: "1 auto" }}>
					<Outlet></Outlet>
				</div>
			</div>
		</div>
	);
};
export default LayoutPage;

src/pages/Users.js

import { Link, useNavigate } from "react-router-dom";

const User = (props) => {
	const navigate = useNavigate();

	const handleClick = () => {
		setTimeout(() => {
			navigate(`123`);
		}, 3000);
	};

	return (
		<div
			style={{
				border: "1px solid black",
				display: "flex",
				flexDirection: "column",
			}}
		>
			User
			{[21, 22].map((num) => {
				return (
					<Link key={num} to={`${num}`}>
						User {num}
					</Link>
				);
			})}
			<button onClick={handleClick}>点击按钮3秒之后跳转</button>
		</div>
	);
};
export default User;

posted @ 2022-04-18 23:49  bcj7wi3kd5h1wd6  阅读(684)  评论(0编辑  收藏  举报