React router第6版的发布指日可待。我想现在是时候好好看看它了 ...
安装
为了使用 React Router,我们需要安装react-router-dom 和history 包:
npm install history react-router-dom@next
注意,react-router-dom 仍处于测试阶段,所以我们明确定义了next 版本。
设置顶层路由
一个路由代表一个应用程序中的一个页面。我们使用React Router的JSX中的一些元素来定义所有的路由:
<BrowserRouter>
<Routes>
<Route path="" element={<HomePage />} />
<Route
path="customers"
element={<CustomersPage />}
/>
<Route
path="products"
element={<ProductsPage />}
/>
<Route
path="products/:id"
element={<ProductsPage />}
/>
</Routes>
</BrowserRouter>
BrowserRouter 元素通常是组件树中最顶层的元素,因为所有其他React Router元素都需要嵌套在它里面。BrowserRouter 为它的后代提供关于当前位置的信息,并将在页面之间执行导航。
一组路由被定义为一个Routes 元素。每个路由都被定义在它的一个Route 元素中。Route 每当位置发生变化时,Routes 找到与当前位置最匹配的path prop的子元素,并渲染element prop中定义的元素。所以,Route 元素有点像if 语句--如果它的路径与当前路径匹配,就会渲染它的元素。
Routes 在以前的React Router版本中, 被取代,一个关键的区别是,其中的 元素的排序不会像以前的 那样影响匹配。 中的匹配更加智能,其优先级基于 与 的具体程度。Switch Route Switch Routes path Route
导航
链接
一个Link 元素在被点击时将会导航到to 道具中指定的路线:
<Link to="buy">Buy</Link>
to 如果路径不是以 开始,则是呈现该路径的相对路径。如果路径以 开始,则是相对于应用程序的根。/ /
Link 是一个 元素,但不会引起服务器端的导航--导航全部发生在浏览器中。a
还有一个元素,我们可以用来做链接,叫做NavLink 。与Link 不同,NavLink 知道它是否处于活动状态:
<nav>
<NavLink to="/" activeClassName="active" end>
Home
</NavLink>
<NavLink
to="customers"
activeClassName="active"
>
Customers
</NavLink>
<NavLink
to="products"
activeClassName="active"
>
Products
</NavLink>
</nav>
一个activeClassName 或activeStyle 的道具可以用来在其路由处于活动状态时为底层的a 元素设置样式。
end 道具意味着只有在当前路径是完全匹配的情况下,NavLink 才会变得活跃。在上面的例子中,如果没有end ,首页将永远是活动的。
编程式导航
程序性导航可以通过useNavigate 钩子来实现。该钩子返回一个函数,该函数将调用导航的路径传递给它:
const navigate = useNavigate();
一个常见的用例是表单提交:
<form
onSubmit={(e) => {
e.preventDefault();
const formData = new FormData(
e.currentTarget
);
// submit form
navigate("/success");
}}
>
<input
name="name"
type="text"
placeholder="name"
/>
<button type="submit">Save</button>
</form>
useNavigate 钩子在第6版中是新的,并且是悬而未决的。
未找到的路由
当没有其他路径与当前路径匹配时,可以定义一个未找到的路径:
<Route path="/*" element={<NotFoundPage />} />
路径/* ,因为它有最弱的优先权,这意味着路由器只有在没有其他路由匹配的情况下才会接收它。
路由参数
参数可以添加到路径的冒号之后:
<Route
path="products/:id"
element={<ProductPage />}
/>
然后,useParams 钩子可以用来从路径中检索参数值:
const { id } = useParams();
const product = products.find(
(p) => p.id === id
);
下属路由
你可以用Routes 元素拥有一组以上的路由。在组件树的更下方,在顶级的Routes 元素内,我们可以有一个额外的Routes 元素:
<Routes>
<Route
path="buy"
element={
<p>Thank you for buying this product!</p>
}
/>
<Route
path="*"
element={
<Link to="buy" className="link">
Buy
</Link>
}
/>
</Routes>
这是在ProductPage 内的以下路线:
<Route
path="products/:id*"
element={<ProductPage />}
/>
第二层路由导致一个购买按钮最初被呈现出来。当这个按钮被点击时,它被替换成这样的信息:谢谢你购买这个产品!。
很好!
嵌套布局
Route 元素可以相互嵌套:
<Route
path="products"
element={<ProductsPage />}
>
<Route path=":id*" element={<ProductPage />} />
</Route>
在上面的例子中,ProductsPage 将被渲染为products 的路径。当路径为products/:id. 时,ProductsPage 和ProductPage 都将被呈现。一个Outlet 元素被用来指定ProductPage 在ProductsPage 中的渲染位置:
<div className="product-list">
{filteredProducts.map(({ id, name }) => (
<Link key={id} to={`/products/${id}`}>
{name}
</Link>
))}
</div>
<Outlet />
这种方法可以产生嵌套式布局,周围的用户界面保持一致,而内部的内容在不同的路线之间变化。
搜索参数
useSearchParams 用来读取和更新搜索参数。它返回一个包含两个值的数组:当前位置的搜索参数和一个更新它们的函数:
let [
searchParams,
setSearchParams,
] = useSearchParams();
searchParams 是一组实用方法,允许检索特定的搜索参数。
setSearchParams 可以用来更新搜索参数:
<form
onSubmit={(e) => {
e.preventDefault();
setSearchParams(
`search=${new FormData(
e.currentTarget
).get("search")}`
);
}}
>
<input
name="search"
type="search"
placeholder="search ..."
/>
</form>
在CodeSandbox中可以找到这些功能的一个工作实例,网址是codesandbox.io/s/react-rou…
总结
第6版中新的Routes 组件是对React Router的一个伟大补充。它的相对匹配使代码更加简洁。用嵌套的Route 元素和Outlet 做嵌套布局的能力是一个很好的提示。非常值得一看!