【笔记】React的路由

前言

A user‑obsessed, standards‑focused, multi‑strategy router you can deploy anywhere.(官网

React通过remix-run/react-router实现路由

下载依赖

1
npm install react-router-dom@6

配置模式

Hash模式

src/index.js
1
2
3
4
5
6
7
8
9
10
import { ReactDOM } from "react-dom/client"
import App from "./App"
import { HashRouter } from "react-router-dom"

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<HashRouter>
<App />
</HashRouter>
);

History模式

src/index.js
1
2
3
4
5
6
7
8
9
10
import { ReactDOM } from "react-dom/client"
import App from "./App"
import { BrowserRouter } from "react-router-dom"

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);

配置路由

以组件的形式配置路由

  • 定义根组件并配置路由
src/components/Home.jsx
1
2
3
4
5
import React from "react"

class Home extends React.Component {}

export default Home;

path:匹配的路径
element:渲染的组件

src/App.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React from "react"
import { Routes, Route } from "react-router-dom"
import Home from "./components/Home"

class App extends React.Component {
render() {
return (
<>
<header></header>
<main>
<Routes>
<Route path="/home" element={<Home />} />
</Routes>
</main>
<footer></footer>
</>
);
}
}

export default App;

通配符匹配

src/App.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React from "react"
import { Routes, Route } from "react-router-dom"
import Home from "./components/Home"
import PageNotFound from "./components/Home"

class App extends React.Component {
render() {
return (
<>
<header></header>
<main>
<Routes>
<Route path="/*" element={<Home />} />
</Routes>
</main>
<footer></footer>
</>
);
}
}

export default App;

动态路由

src/App.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React from "react"
import { Routes, Route } from "react-router-dom"
import Home from "./components/Home"
import PageNotFound from "./components/Home"

class App extends React.Component {
render() {
return (
<>
<header></header>
<main>
<Routes>
<Route path="/home/:key" element={<Home />} />
</Routes>
</main>
<footer></footer>
</>
);
}
}

export default App;

以配置的形式配置路由

src/components/Home.jsx
1
2
3
4
5
import React from "react"

class Home extends React.Component {}

export default Home;
src/router/index.js
1
2
3
4
5
6
7
8
9
10
import Home from "../components/Home"

const routes = [
{
path: "/home",
element: <Home />,
},
];

export default routes;
src/App.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React from "react"
import { useRoutes } from "react-router-dom"
import routes from "./router"

class App extends React.Component {
render() {
return (
<>
<header></header>
<main>
{ useRoutes(routes) }
</main>
<footer></footer>
</>
);
}
}

export default App;

跳转路由

通过组件跳转路由

Link组件

to:跳转的路径
replace:是否是Replace操作

false:缺省值,Push操作,可以返回
true:Replace操作,不可以返回

reloadDocument:是否刷新页面

false:缺省值,不刷新页面
true:刷新页面

src/components/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from "react"
import { Link } from "react-router-dom"

class Component extends React.Component {
render() {
return (
<>
<Link to="/home">首页</Link>
</>
);
}
}

export default App;
  • 渲染结果
1
2
3
<div class="nav">
<a href="/home">首页</a>
</div>
src/components/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from "react"
import { NavLink } from "react-router-dom"

class Component extends React.Component {
render() {
return (
<>
<NavLink to="/home">首页</Link>
</>
);
}
}

export default App;
  • 渲染结果
1
2
3
<div class="nav">
<a class="active" href="/home">首页</a>
</div>
直接定义active类的样式
src/components/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from "react"
import { NavLink } from "react-router-dom"

class Component extends React.Component {
render() {
return (
<>
<NavLink to="/home" style={(param) => ({ color: param.isActive ? "red" : "" })}>首页</Link>
</>
);
}
}

export default App;
自定义class名
src/components/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from "react"
import { NavLink } from "react-router-dom"

class Component extends React.Component {
render() {
return (
<>
<NavLink to="/home" className={(param) => param.isActive ? "active" : "" }>首页</Link>
</>
);
}
}

export default App;
  • 只要出现<Navigate />立即重定向到指定页面
src/components/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from "react"
import { Navigate } from "react-router-dom"

class Component extends React.Component {
render() {
return (
<>
<Navigate to="/home" />
</>
);
}
}

export default App;
  • 可以用于重定向到默认页面
src/components/Home.jsx
1
2
3
4
5
import React from "react"

class Home extends React.Component {}

export default Home;
src/App.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React from "react"
import { Routes, Route } from "react-router-dom"
import Home from "./components/Home"

class App extends React.Component {
render() {
return (
<>
<header></header>
<main>
<Routes>
<Route path="/" element={<Navigate to="/home" />} />
<Route path="/home" element={<Home />} />
</Routes>
</main>
<footer></footer>
</>
);
}
}

export default App;

通过JS跳转路由

函数式组件

  • 在函数式组件中,通过Hooks的形式跳转路由
src/components/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
import { useNavigate } from "react-router-dom"

function Component(props) {
const navigate = useNavigate();

return (
<>
<button onClick={() => navigate("/home")}>首页</button>
</>
);
}

export default Component;
配置是否是Replace操作

replace:是否是Replace操作

false:缺省值,Push操作,可以返回
true:Replace操作,不可以返回

src/components/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
import { useNavigate } from "react-router-dom"

function Component(props) {
const navigate = useNavigate();

return (
<>
<button onClick={() => navigate("/home", { replace: false })}>首页</button>
</>
);
}

export default Component;
通过跳转层级跳转

-1:正数表示前进次数,负数表示后退次数

src/components/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
import { useNavigate } from "react-router-dom"

function Component(props) {
const navigate = useNavigate();

return (
<>
<button onClick={() => navigate(-1)}>首页</button>
</>
);
}

export default Component;

类组件

  • 通过高阶组件传递Hooks实现路由跳转
src/hoc/withRouter.jsx
1
2
3
4
5
6
7
8
9
10
import { useNavigate } from "react-router-dom"

function withRouter(WrapperComponent) {
return function (props) {
const navigate = useNavigate();
return <WrapperComponent { ...props } navigate={ navigate } />;
}
}

export default withRouter;
src/components/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from "react"
import withRouter from "../hoc/withRouter"

class Component extends React.Component {
render() {
return (
<>
<button onClick={() => this.props.navigate("/home")}>首页</button>
</>
);
}
}

export default withRouter(Component);

二级路由

src/components/Son.jsx
1
2
3
4
5
import React from "react"

class Son extends React.Component {}

export default Son;
src/components/Daughter.jsx
1
2
3
4
5
import React from "react"

class Daughter extends React.Component {}

export default Daughter;
src/components/Father.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React from "react"
import { Link, Outlet } from "react-router-dom"

class Father extends React.Component {
render() {
return (
<>
<Link to="/father/son">子页面1</Link>
<Link to="/father/daughter">子页面2</Link>

{/* 父组件中作为子组件的占位组件 */}
<Outlet />
</>
);
}
}

export default Father;

配置路由

以组件的形式配置路由

src/App.jsx
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 { Routes, Route } from "react-router-dom"
import Father from "./components/Father"
import Son from "./components/Son"
import Daughter from "./components/Daughter"

class App extends React.Component {
render() {
return (
<>
<header></header>
<main>
<Routes>
<Route path="/father" element={<Father />}>
<Route path="/father/son" element={<Son />} />
<Route path="/father/daughter" element={<Daughter />} />
</Route>
</Routes>
</main>
<footer></footer>
</>
);
}
}

export default App;
  • 重定向到默认页面
src/App.jsx
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
import React from "react"
import { Routes, Route } from "react-router-dom"
import Father from "./components/Father"
import Son from "./components/Son"
import Daughter from "./components/Daughter"

class App extends React.Component {
render() {
return (
<>
<header></header>
<main>
<Routes>
<Route path="/" element={<Navigate to="/father" />} />
<Route path="/father" element={<Father />}>
<Route path="/father" element={<Navigate to="/father/son" />} />
<Route path="/father/son" element={<Son />} />
<Route path="/father/daughter" element={<Daughter />} />
</Route>
</Routes>
</main>
<footer></footer>
</>
);
}
}

export default App;

以配置的形式配置路由

src/router/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import Father from "../components/Father"
import Son from "../components/Son"
import Daughter from "../components/Daughter"

const routes = [
{
path: "/father",
element: <Father />
children: [
{
path: "/father/son",
element: <Son />
},
{
path: "/father/daughter",
element: <Daughter />
}
]
}
];

export default routes;
src/App.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React from "react"
import { useRoutes } from "react-router-dom"
import routes from "./router"

class App extends React.Component {
render() {
return (
<>
<header></header>
<main>
{ useRoutes(routes) }
</main>
<footer></footer>
</>
);
}
}

export default App;

获取参数

动态路由参数

request
1
GET http://127.0.0.1:80/home/value

配置动态路由

传送门

函数式组件

  • 在函数式组件中,通过Hooks的形式获取动态路由参数
src/components/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
import { useParams } from "react-router-dom"

function Component(props) {
const params = useParams();

return (
<>
{ params.key }
</>
);
}

export default Component;

类组件

  • 通过高阶组件传递Hooks实现获取动态路由参数
src/hoc/withRouter.jsx
1
2
3
4
5
6
7
8
9
10
import { useParams } from "react-router-dom"

function withRouter(WrapperComponent) {
return function (props) {
const params = useParams();
return <WrapperComponent { ...props } params={ params } />;
}
}

export default withRouter;
src/components/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from "react"
import withRouter from "../hoc/withRouter"

class Component extends React.Component {
render() {
return (
<>
{ this.props.params.get("key", "default") }
</>
);
}
}

export default withRouter(Component);

查询字符串

request
1
GET http://127.0.0.1:80/home?key=value

函数式组件

  • 在函数式组件中,通过Hooks的形式获取动态路由参数
src/components/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { useSearchParams } from "react-router-dom"

function Component(props) {
const [ searchParams, setSearchParams ] = useSearchParams();
const searchParamsObject = Object.fromEntries(searchParams);

return (
<>
{ searchParamsObject.key }
</>
);
}

export default Component;

类组件

  • 通过高阶组件传递Hooks实现获取动态路由参数
src/hoc/withRouter.jsx
1
2
3
4
5
6
7
8
9
10
11
import { useSearchParams } from "react-router-dom"

function withRouter(WrapperComponent) {
return function (props) {
const [ searchParams, setSearchParams ] = useSearchParams();
const searchParamsObject = Object.fromEntries(searchParams);
return <WrapperComponent { ...props } searchParamsObject={ searchParamsObject } />;
}
}

export default withRouter;
src/components/Component.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from "react"
import withRouter from "../hoc/withRouter"

class Component extends React.Component {
render() {
return (
<>
{ this.props.searchParams.key }
</>
);
}
}

export default withRouter(Component);

完成