Open wuxianqiang opened 2 years ago
npm install react-router-dom@6
import { render } from "react-dom"; import { BrowserRouter, Routes, Route } from "react-router-dom"; // import your route components too render( <BrowserRouter> <Routes> <Route path="/" element={<App />}> <Route index element={<Home />} /> <Route path="teams" element={<Teams />}> <Route path=":teamId" element={<Team />} /> <Route path="new" element={<NewTeamForm />} /> <Route index element={<LeagueStandings />} /> </Route> </Route> </Routes> </BrowserRouter>, document.getElementById("root") );
在以前版本的 React Router 中,当多个路由匹配一个不明确的 URL 时,你必须以某种方式对你的路由进行排序才能得到正确的渲染。V6 更聪明,会选择最具体的匹配,所以你不必再担心了。例如,URL /teams/new 匹配这两个路由:
/teams/new
<Route path="teams/:teamId" element={<Team />} /> <Route path="teams/new" element={<NewTeamForm />} />
由于 teams/new 比 /teams/:teamId 是更具体的匹配 ,因此 <NewTeamForm /> 将呈现。
teams/new
/teams/:teamId
<NewTeamForm />
使用 Link 让用户更改 URL 或者用 useNavigate 自己做跳转:
import { Link } from "react-router-dom"; function Home() { return ( <div> <h1>Home</h1> <nav> <Link to="/">Home</Link> |{" "} <Link to="about">About</Link> </nav> </div> ); }
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> ); }
在路由路径中使用 :style 语法,组件中用 useParams() 取值:
:style
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>; }
请注意,路径中 :invoiceId 和参数的键 params.invoiceId 匹配,key 值必须对应。
:invoiceId
params.invoiceId
一个非常常见的用例是在组件呈现时获取数据:
function Invoice() { let { invoiceId } = useParams(); let invoice = useFakeFetch(`/api/invoices/${invoiceId}`); return invoice ? ( <div> <h1>{invoice.customerName}</h1> </div> ) : ( <Loading /> ); }
这是 React Router 最强大的功能之一,因此您不必处理复杂的布局代码。绝大多数布局都与 URL 的片段耦合,而 React Router 完全符合了这一点。
路由可以相互嵌套,它们的路径也会嵌套(子继承父)。
function App() { return ( <Routes> <Route path="invoices" element={<Invoices />}> <Route path=":invoiceId" element={<Invoice />} /> <Route path="sent" element={<SentInvoices />} /> </Route> </Routes> ); }
此路由配置定义了三个路由路径:
"/invoices" "/invoices/sent" "/invoices/:invoiceId"
当 URL 是"/invoices/sent", 组件树为:
<App> <Invoices> <SentInvoices /> </Invoices> </App>
当 URL 为"/invoices/123",组件树为:
<App> <Invoices> <Invoice /> </Invoices> </App>
请注意随 URL (<SentInvoices>和<Invoice>)更改的内部组件。父路由 ( <Invoices>) 负责确保匹配的子路由使用了 <Outlet>,这是完整的示例:
<SentInvoices>
<Invoice>
<Invoices>
<Outlet>
import { Routes, Route, Outlet } from "react-router-dom"; function App() { return ( <Routes> <Route path="invoices" element={<Invoices />}> <Route path=":invoiceId" element={<Invoice />} /> <Route path="sent" element={<SentInvoices />} /> </Route> </Routes> ); } function Invoices() { return ( <div> <h1>Invoices</h1> <Outlet /> </div> ); } function Invoice() { let { invoiceId } = useParams(); return <h1>Invoice {invoiceId}</h1>; } function SentInvoices() { return <h1>Sent Invoices</h1>; }
嵌套的 url 路径映射到嵌套的组件树。这非常适合创建在布局中具有持久导航且内部部分随 URL 变化的 UI。您会注意到许多网站都具有多层布局嵌套。
索引路由可以被认为是“默认子路由”。当父路由有多个子路由,但 URL 仅在父路由的路径上时,您可能希望将某些内容渲染到页面中。
function App() { return ( <Routes> <Route path="/" element={<Layout />}> <Route path="invoices" element={<Invoices />} /> <Route path="activity" element={<Activity />} /> </Route> </Routes> ); } function Layout() { return ( <div> <GlobalNav /> <main> <Outlet /> </main> </div> ); }
这个页面在“/invoices”和“/activity”上看起来很棒,但在“/”它只是一个空白页面,<main> 因为那里没有子路由渲染。为此,我们可以添加一个索引路由:
<main>
function App() { return ( <Routes> <Route path="/" element={<Layout />}> <Route index element={<Activity />} /> <Route path="invoices" element={<Invoices />} /> <Route path="activity" element={<Activity />} /> </Route> </Routes> ); }
现在在“/”处,<Activity> 元素将在 Outlet 出口内呈现。
<Activity>
您可以在路由层次结构的任何级别拥有一个索引路由,当父级匹配但其他子级都不匹配时,该索引路由将呈现。
function App() { return ( <Routes> <Route index element={<Home />} /> <Route path="dashboard" element={<Dashboard />}> <Route index element={<DashboardHome />} /> <Route path="invoices" element={<DashboardInvoices />} /> </Route> </Routes> ); }
相对 <Link to> 值(不以 / 开头)是相对于渲染它们的路径的路径。下面的两个链接将链接到 /dashboard/invoices 和 /dashboard/team 因为它们在 <Dashboard>. 当您更改父级的 URL 或重新排列您的组件时,这非常好,因为您的所有链接都会自动更新。
<Link to>
<Dashboard>
import { Routes, Route, Link, Outlet } from "react-router-dom"; function Home() { return <h1>Home</h1>; } function Dashboard() { return ( <div> <h1>Dashboard</h1> <nav> <Link to="invoices">Invoices</Link>{" "} <Link to="team">Team</Link> </nav> <hr /> <Outlet /> </div> ); } function Invoices() { return <h1>Invoices</h1>; } function Team() { return <h1>Team</h1>; } function App() { return ( <Routes> <Route path="/" element={<Home />} /> <Route path="dashboard" element={<Dashboard />}> <Route path="invoices" element={<Invoices />} /> <Route path="team" element={<Team />} /> </Route> </Routes> ); }
当没有其他路由与 URL 匹配时,您可以使用path="*". 此路由将匹配任何 URL,但具有最弱的优先级,因此路由仅在没有其他路由匹配时才会选择它。
function App() { return ( <Routes> <Route path="/" element={<Home />} /> <Route path="dashboard" element={<Dashboard />} /> <Route path="*" element={<NotFound />} /> </Routes> ); }
尽管您应该 <Router> 在应用程序中只拥有一个,但您可以 <Routes> 在任何需要的地方拥有任意数量的。每个 <Routes> 元素独立于其他元素运行,并选择一个子路由进行渲染。
<Router>
<Routes>
function App() { return ( <div> <Sidebar> <Routes> <Route path="/" element={<MainNav />} /> <Route path="dashboard" element={<DashboardNav />} /> </Routes> </Sidebar> <MainContent> <Routes> <Route path="/" element={<Home />}> <Route path="about" element={<About />} /> <Route path="support" element={<Support />} /> </Route> <Route path="dashboard" element={<Dashboard />}> <Route path="invoices" element={<Invoices />} /> <Route path="team" element={<Team />} /> </Route> <Route path="*" element={<NotFound />} /> </Routes> </MainContent> </div> ); }
安装
配置路由
在以前版本的 React Router 中,当多个路由匹配一个不明确的 URL 时,你必须以某种方式对你的路由进行排序才能得到正确的渲染。V6 更聪明,会选择最具体的匹配,所以你不必再担心了。例如,URL
/teams/new
匹配这两个路由:由于
teams/new
比/teams/:teamId
是更具体的匹配 ,因此<NewTeamForm />
将呈现。导航
使用 Link 让用户更改 URL 或者用 useNavigate 自己做跳转:
读取 URL 参数
在路由路径中使用
:style
语法,组件中用useParams()
取值:请注意,路径中
:invoiceId
和参数的键params.invoiceId
匹配,key 值必须对应。一个非常常见的用例是在组件呈现时获取数据:
嵌套路由
这是 React Router 最强大的功能之一,因此您不必处理复杂的布局代码。绝大多数布局都与 URL 的片段耦合,而 React Router 完全符合了这一点。
路由可以相互嵌套,它们的路径也会嵌套(子继承父)。
此路由配置定义了三个路由路径:
当 URL 是"/invoices/sent", 组件树为:
当 URL 为"/invoices/123",组件树为:
请注意随 URL (
<SentInvoices>
和<Invoice>
)更改的内部组件。父路由 (<Invoices>
) 负责确保匹配的子路由使用了<Outlet>
,这是完整的示例:嵌套的 url 路径映射到嵌套的组件树。这非常适合创建在布局中具有持久导航且内部部分随 URL 变化的 UI。您会注意到许多网站都具有多层布局嵌套。
索引路由
索引路由可以被认为是“默认子路由”。当父路由有多个子路由,但 URL 仅在父路由的路径上时,您可能希望将某些内容渲染到页面中。
这个页面在“/invoices”和“/activity”上看起来很棒,但在“/”它只是一个空白页面,
<main>
因为那里没有子路由渲染。为此,我们可以添加一个索引路由:现在在“/”处,
<Activity>
元素将在 Outlet 出口内呈现。您可以在路由层次结构的任何级别拥有一个索引路由,当父级匹配但其他子级都不匹配时,该索引路由将呈现。
相对链接
相对
<Link to>
值(不以 / 开头)是相对于渲染它们的路径的路径。下面的两个链接将链接到 /dashboard/invoices 和 /dashboard/team 因为它们在<Dashboard>
. 当您更改父级的 URL 或重新排列您的组件时,这非常好,因为您的所有链接都会自动更新。"Not Found" 路由
当没有其他路由与 URL 匹配时,您可以使用path="*". 此路由将匹配任何 URL,但具有最弱的优先级,因此路由仅在没有其他路由匹配时才会选择它。
多组路由
尽管您应该
<Router>
在应用程序中只拥有一个,但您可以<Routes>
在任何需要的地方拥有任意数量的。每个<Routes>
元素独立于其他元素运行,并选择一个子路由进行渲染。