React学习之——Router(v6)
安装
$ npm install react-router-dom@6
配置路由
在入口文件导入BrowserRouter文件,并包裹根组件:
import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import App from './App'
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
)
在根组件使用 Routes 和 Route 定义路由:
import React from 'react'
import { Routes, Route } from 'react-router-dom'
import { Home, About } from './components'
function App() {
return (
<div className="App">
<h1>Welcome to React Router!</h1>
<Routes>
<Route path="/" element={<Home />} />
<Route path="about" element={<About />} />
</Routes>
</div>
)
}
export default App
导航
通过 Link 组件导航:
import { Link } from 'react-router-dom'
function Home() {
return (
<main>
<h2>Home</h2>
<Link to="/about">About</Link>
</main>
)
}
function About() {
return (
<main>
<h2>About</h2>
<Link to="/">Home</Link>
</main>
)
}
或者使用 useNavigate Hook 导航
import { useNavigate } from 'react-router-dom'
function About() {
let navigate = useNavigate()
return (
<main>
<h2>About</h2>
<button onClick={() => {
navigate('/')
}}>Home</button>
</main>
)
}
读取路由参数
使用 :style 语法配置路由路径,使用 useParams Hook 读取参数;带参数路由优先级比完全相等的优先级低
import { Routes, Route, useParams } from "react-router-dom"
function Article() {
let params = useParams()
return (
<main>
<h2>Article</h2>
<p>id: { params.id }</p>
</main>
)
}
function App() {
return (
<div className="App">
<h1>Welcome to React Router!</h1>
<Routes>
<Route path="/article/:id" element={<Article />} />
</Routes>
</div>
)
}
嵌套路由
嵌套 Route 组件, 在父组件中使用 Outlet 组件渲染子路由组件:
function Contact() {
return (
<main>
<h2>Contact</h2>
<Link to="/contact/address">Address</Link>
<Link to="/contact/phone">Phone</Link>
<Outlet></Outlet>
</main>
)
}
function Address() {
return <div>This is address: xxxxxxxxxxx</div>
}
function Phone() {
return <div>This is phone: xxxxxxxxxxx</div>
}
function App() {
return (
<div className="App">
<h1>Welcome to React Router!</h1>
<Routes>
<Route path="/contact" element={<Contact />}>
<Route path="address" element={<Address />}></Route>
<Route path="phone" element={<Phone />}></Route>
</Route>
</Routes>
</div>
)
}
索引路由
当 URL 匹配父路由而不匹配子路由时,可以添加一个索引路由作为默认子路由来将组件渲染到出口。
在子 Route 组件中添加 index 属性:
function ContactIndex() {
return (
<div>ContactIndex</div>
)
}
function App() {
return (
<div className="App">
<h1>Welcome to React Router!</h1>
<Routes>
<Route path="/contact" element={<Contact />}>
<Route index element={<ContactIndex />}></Route>
<Route path="address" element={<Address />}></Route>
<Route path="phone" element={<Phone />}></Route>
</Route>
</Routes>
</div>
)
}
相对路由
不以斜杆 / 开头的 URL 的路由会被视为相对路由,修改上面的 Contact 组件:
function Contact() {
return (
<main>
<h2>Contact</h2>
<Link to="address">Address</Link>
<Link to="phone">Phone</Link>
<Outlet></Outlet>
</main>
)
}
404 路由
用于呈现没有其他路由与 URL 匹配时的路由组件,此路由优先级最低;嵌套路由也可以使用 404 路由:
function App() {
return (
<div className="App">
<h1>Welcome to React Router!</h1>
<Routes>
<Route path="*" element={<NotFound />} />
</Routes>
</div>
)
}
多组路由
一个应用程序可以有任意数量的 Routes 组件。
后代路由
Routes 组件可以放置在任何地方,包括在另一个组件树的深处,它将自动构建在呈现它们的路由的路径上,这时需要在父路由路径的末尾加上星号*:
function Article() {
return (
<main>
<h2>Article</h2>
<Routes>
<Route path="comment" element={<Comment />} />
<Route path="statistics" element={<Statistics />} />
</Routes>
</main>
)
}
function App() {
return (
<div className="App">
<h1>Welcome to React Router!</h1>
<Routes>
<Route path="/article/:id/*" element={<Article />} />
</Routes>
</div>
)
}
完整示例代码
import { Routes, Route, Link, useParams, Outlet } from 'react-router-dom'
import './App.scss'
function Nav() {
return (
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/article/1">Article</Link>
<Link to="/contact">Contact</Link>
</nav>
)
}
function Home() {
return (
<main>
<h2>Home</h2>
<Nav />
</main>
)
}
function About() {
return (
<main>
<h2>About</h2>
<Nav />
</main>
)
}
function Comment() {
return <div>This is comment list.</div>
}
function Statistics() {
return <div>This is statistics.</div>
}
function Article() {
let params = useParams()
return (
<main>
<h2>Article</h2>
<Nav />
<p>id: {params.id}</p>
<Link to="comment">Comment</Link>
<Link to="statistics">Statistics</Link>
<Routes>
<Route path="comment" element={<Comment />} />
<Route path="statistics" element={<Statistics />} />
</Routes>
</main>
)
}
function Contact() {
return (
<main>
<h2>Contact</h2>
<Nav />
<Link to="address">Address</Link>
<Link to="phone">Phone</Link>
<Outlet></Outlet>
</main>
)
}
function ContactIndex() {
return <div>ContactIndex</div>
}
function Address() {
return <div>This is address: xxxxxxxxxxx</div>
}
function Phone() {
return <div>This is phone: xxxxxxxxxxx</div>
}
function NotFound() {
return <div>404 Not Found</div>
}
function App() {
return (
<div className="App">
<h1>Welcome to React Router!</h1>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />}>
<Route index element={<ContactIndex />}></Route>
<Route path="address" element={<Address />}></Route>
<Route path="*" element={<NotFound />} />
<Route path="phone" element={<Phone />}></Route>
</Route>
<Route path="/article/:id/*" element={<Article />} />
<Route path="*" element={<NotFound />} />
</Routes>
</div>
)
}
export default App
概念定义
-
URL - 地址栏中的URL。很多人交替使用术语“URL”和“route”,但这不是 React Router 中的路由,它只是一个URL。
-
Location - 这是一个特定于路由器的对象,基于内置浏览器的 window.location 对象。它代表“用户所在的位置”。它主要是 URL 的一种对象表示形式,但它有更多的含义。
-
Location State - 与URL中未编码的 location 保持一致的值。与 hash 或 search params (URL中编码的数据)非常相似,存储在浏览器的内存中。
-
History Stack - 当用户导航时,浏览器会跟踪堆栈中的每个位置。如果在浏览器中单击并按住“后退”按钮,您可以在那里看到浏览器的历史堆栈。
-
Client Side Routing (CSR) - 一个普通的HTML文档可以链接到其他文档,浏览器自己处理历史堆栈。Client Side Routing 使开发人员能够操纵浏览器历史堆栈,而无需向服务器发出文档请求。
-
History - 一个对象,允许React Router订阅URL中的更改,并提供 API 以编程方式操作浏览器历史堆栈。
-
History Action - pop、push 或 replace。用户可以出于以下三个原因之一访问 URL。将新条目添加到历史堆栈时的 push(通常是链接单击或程序员强制导航)。replace 与之类似,只是它替换堆栈上的当前条目,而不是推送一个新条目。最后,当用户单击浏览器中的后退或前进按钮时,会出现 pop 操作。
-
Segment - URL 或 path pattern 中 / 字符之间的部分。例如,“/users/123” 有两个 segment。
-
Path Pattern - 这些看起来像 URL,但可以有特殊字符来将URL与路由匹配,比如动态 segment “/users/:userId” 或星形 segment “/docs/*”。它们不是URL,它们是路由器将匹配的模式。
-
Dynamic Segment - 动态的 path pattern 的 segment ,这意味着它可以匹配该 segment 中的任何值。例如,模式 /users/:userId 将匹配像 /users/123 这样的 URL。
-
URL Params - 与动态 segment 匹配的URL解析值。
-
Router - 有状态的顶级组件,使所有其他组件和 hook 工作。
-
Route Config - routes objects 树,将根据当前 location 进行排序和匹配(嵌套),以创建 route matches 的分支。
-
Route - 通常具有 { path,Element } 或形状的对象或 Route Element。path 是一种 path pattern。当 path pattern 与当前 URL 匹配时,将呈现元素。
-
Route Element - 或者。通过读取此元素的 props 来创建 Route,但在其他情况下不执行任何操作。
-
Nested Routes - 因为路由可以有子路由,每个路由通过 segments 定义 URL 的一部分,所以单个 URL 可以匹配树的嵌套“分支”中的多个路由。这样可以通过 Outlet、Relative links 等实现自动布局嵌套。
-
Relative links - 不以 / 开头的链接将继承渲染它们的最近路径。这使得链接到更深层次的 URL 变得很容易,而无需知道并构建整个路径。
-
Match - 当路由与 URL 匹配时保存信息的对象,如匹配的 URL 参数和路径名。
-
Matches - 与当前 location 匹配的路由数组(或路由配置的分支)。此结构支持嵌套路由。
-
Parent Route - 带有子路由的路由。
-
Outlet - 子路由组件的渲染出口。
-
Index Route - 一个没有子路径的路由,匹配父路由 URL 时渲染。
- Layout Route - 一种没有 path 的父路由,专门用于在特定布局中对子路由进行分组。