React react-router-dom

React react-router-dom

一月 24, 2021

React 路由 react-router-dom

  1. 安装
1
2
$ yarn add react-router-dom
$ yarn add @types/react-router-dom
  1. 选择路由模式

    • 目录 src/index.tsx 中写
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      // 设置路由模式
      // react-router-dom提供两种路由模式 HashRouter / BrowserRouter
      import { BrowserRouter } from "react-router-dom";
      ReactDOM.render(
      <BrowserRouter>
      {" "}
      // 用标签包裹起来
      <React.StrictMode>
      <App />
      </React.StrictMode>
      </BrowserRouter>,
      document.getElementById("root")
      );
  2. 创建路由组件

    1. src/router/index.tsx 组件用于路由渲染区域
    2. src/components/tab/index.tsx 组件用于导航区域
    3. src/App.tsx 引入这两个组件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import React from "react";
    import Tab from "./components/tab";
    import RouterComp from "./router";

    export default function App() {
    return (
    <div>
    {/* 导航区域 */}
    <Tab />
    {/* 路由区域 */}
    <RouterComp />
    </div>
    );
    }

打造路由表

  1. 在 router 文件下创建 routes.ts 用于书写路由表
  2. 在 src 文件夹下创建 pages,用于存放路由组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 路由表 渲染导航区域

import { lazy } from "react";

interface Routes {
path?: any;
component?: any;
title?: string;
children?: Routes[];
}

const routes: Routes[] = [
{
path: "/home",
component: lazy(() => import("../pages/Home")),
title: "首页",
},
{
path: "/about",
component: lazy(() => import("../pages/About")),
title: "关于",
},
{
path: "/cates",
component: lazy(() => import("../pages/Cates")),
title: "分类",
},
{
path: "/mine",
component: lazy(() => import("../pages/Mine")),
title: "我的",
},
{
path: "",
component: lazy(() => import("../pages/NotFound")),
},
];

export default routes;

React.lazy

用于懒加载组件的

Tab 区域

  1. 需要从 react-router-dom 引入 NavLink
  2. 引入 routes,通过 routes 数据遍历渲染
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React from "react";
import { NavLink } from "react-router-dom";
import routes from "../../router/routes";

export default function Tab() {
return (
<div>
<header>
<ul>
{routes.map((item, index) => (
<li key={index}>
<NavLink to={item.path}>{item.title}</NavLink>
</li>
))}
</ul>
</header>
</div>
);
}
  1. to 属性,用于路径跳转
  2. activeClassName 属性,激活时使用的类名

路由渲染区域

  1. 从 react-router-dom 引入 Route
  2. 从 react 引入 Suspense
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React, { Suspense } from "react"; // Suspense和lazy一起用
import routes from "./routes";
import { Route, Switch } from "react-router-dom";
export default function RouterComp() {
return (
<div>
<Suspense fallback={<div>组件切换中...</div>}>
<Switch>
{routes.map((item, index) => (
<Route key={index} path={item.path} component={item.component} />
))}
</Switch>
</Suspense>
</div>
);
}

Route

类似于 vue 中的 router-view,里面有 path,component 属性

Switch

一次只渲染一个 Route

React.Suspense

转场组件,和 lazy 一起用,解决中间转场空白期

重定向

1
<Redirect from="/" to="/home" exact />

Redirect 重定向组件

  1. from 当前路由路径
  2. to 目标路由路径
  3. exact 路径完全匹配
  4. 它是单标签,不需要包裹路由,放在 Switch 下方

二级路由

  1. 在路由表里增加子路由并在 pages 打造路由实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// routes.ts
{
path: "/home",
component: lazy(() => import("../pages/Home")),
title: "首页",
children: [{
path: '/home/hot',
component: lazy(() => import('../pages/Home/Hot')),
title: '热门商品'
},{
path: '/home/classic',
component: lazy(() => import('../pages/Home/Classic')),
title: '经典商品'
}]
},
  1. 上述子路由在 Home 路由中,所以要在 Home 组件渲染路由
  • 子路由导航区域
  • 子路由渲染区域
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import React from "react";
import { NavLink, Route, Redirect, Switch } from "react-router-dom";
import routes from "../../router/routes";

interface P {
location: {
pathname: string;
};
}
export default function Home(props: P) {
const { pathname } = props.location;
// console.log(pathname); // 当前路径的string值
// 过滤出children数据
const { children } = routes.filter((item) => pathname.includes(item.path))[0];
// console.log(children);

return (
<div>
<h3>首页</h3>
{/* 子路由导航 */}
<ul>
{children?.map((item, index) => (
<li key={index}>
<NavLink to={item.path}>{item.title}</NavLink>
</li>
))}
</ul>
{/* 子路由组件渲染 */}
<div>
<Switch>
<Redirect from="/home" to="/home/hot" exact />
{children?.map((item, index) => (
<Route
key={index}
path={item.path}
component={item.component}
></Route>
))}
</Switch>
</div>
</div>
);
}

声明式跳转/命令式跳转(编程式导航)

声明式跳转

  1. Link 中的 to
  2. NavLink 中的 to
  3. a 标签(但它会刷新)

编程式导航

  1. 函数组件使用钩子函数 useHistory
  • 实例化 history.push/replace/goBack
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import React from "react";
import { useHistory } from "react-router-dom";

export default function About() {
const history = useHistory();
return (
<div>
<h3>关于我们</h3>
<button
onClick={() => {
history.push("/cates");
}}
>
跳转到cates
</button>
<br />
<button
onClick={() => {
history.goBack();
}}
>
返回
</button>
</div>
);
}
  1. 类组件
  • 通过属性 this.props.history.goBack
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React, { Component } from "react";

interface P {
history: {
goBack: () => void;
};
}

export default class index extends Component<P> {
render() {
return (
<div>
<h3>分类</h3>
<button onClick={this.props.history.goBack}>返回</button>
</div>
);
}
}

动态路由

  1. 动态传参
    • 通过 Link 里面 to 可以写对象 pathname/search/state/hash
  2. 动态接参
    • 通过 useLocation,实例化后有个 location.search 可以得到?之后的字符串,通过 qs.parse 转换成对象并解构出参数