二、Routing
大约 4 分钟约 1204 字
(一)Routing in a React app
- 安装第三方路由库
- 创建
routes.js
路由配置文件 - 对于每条路由,创建一个组件文件,导出该组件,在
routes.js
中导入它,并使用path
属性指定路由
(二)Routing in a Next.js app
- 基于文件系统的路由机制
- 当将文件添加到项目中的
pages
文件夹时,它将自动成为可用的路由 - 通过将文件名与嵌套文件夹结构混合和匹配,几乎可以定义最常见的路由模式
Route with Pages
:页面路由Nested routes
:嵌套路由Dynamic routes
:动态路由Catch-all routes
:全方位路由Navigate from the UI
:从 UI 组件中导航Programmatically navigate b/w Pages
:编程导航 b/w 页面
(三)Routing with Pages —— 页面路由
- 路由路径等同于
pages
文件夹下定义的文件名 - 基于页面的路由机制,页面根据其文件名与路由相关联
pages/_app.js
1. function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
}
export default MyApp;
pages/index.js
2. - 访问
localhost:3000/
function Home() {
return <h1>Home Page</h1>;
}
export default Home;
pages/about.js
3. - 访问
localhost:3000/about
function About() {
return <h1>About Page</h1>;
}
export default About;
pages/profile.js
4. - 访问
localhost:3000/profile
function Profile() {
return <h1>Profile Page</h1>;
}
export default Profile;
(四)Nested Routes —— 嵌套路由
pages
下文件夹将映射为路由多级路径- 嵌套路由——嵌套文件夹结构,文件将自动以相同的方式在 URL 中映射路由
pages/blog.js
1. - 访问
localhost:3000/blog
function Blog() {
return <h1>Blog Page</h1>;
}
export default Blog;
- 将该文件移动到
pages/blog
目录下,并重命名为index.js
,访问localhost:3000/blog
依旧能访问该页面 - 推荐
pages/blog/first.js
2. - 访问
localhost:3000/blog/first
function FirstBlog() {
return <h1>First Blog Page</h1>;
}
export default FirstBlog;
pages/blog/second.js
3. - 访问
localhost:3000/blog/second
function SecondBlog() {
return <h1>Second Blog Page</h1>;
}
export default SecondBlog;
(五)Dynamic Routes —— 动态路由
- 使用
[]
定义文件名,将在渲染时根据[]
内的参数动态形成路由路径 - 使用
useRouter
钩子函数获取文件名参数 - 路由路径匹配到页面路由和动态路由时,优先渲染页面路由
pages/product/index.js
1. - 访问
localhost:3000/product
function ProductList() {
return (
<>
<h2>Product 1</h2>
<h2>Product 2</h2>
<h2>Product 3</h2>
</>
);
}
export default ProductList;
pages/product/[productId].js
2. - 访问
localhost:3000/product/1
- 访问
localhost:3000/product/2
- 访问
localhost:3000/product/3
- 访问
localhost:3000/product/100
import { useRouter } from "next/router";
function ProductDetail() {
const router = useRouter();
const productId = router.query.productId;
return <h1>Details about product {productId}</h1>;
}
export default ProductDetail;
(六)Nested Dynamic Routes —— 嵌套动态路由
- 使用
[]
定义文件夹名,将在渲染时根据[]
内的参数动态形成多级路由路径
pages/product/[productId]/index.js
1. - 访问
localhost:3000/product/1
- 访问
localhost:3000/product/2
- 访问
localhost:3000/product/3
- 访问
localhost:3000/product/100
import { useRouter } from "next/router";
function ProductDetail() {
const router = useRouter();
const productId = router.query.productId;
return <h1>Details about product {productId}</h1>;
}
export default ProductDetail;
pages/product/[productId]/review/[reviewId].js
2. - 访问
localhost:3000/product/1/review/1
- 访问
localhost:3000/product/2/review/2
- 访问
localhost:3000/product/3/review/3
- 访问
localhost:3000/product/100/review/5
import { useRouter } from "next/router";
function Review() {
const router = useRouter();
const { productId, reviewId } = router.query;
return (
<h1>
Review {reviewId} for product {productId}
</h1>
);
}
export default Review;
(七)Catch All Routes —— 全方位路由
- 使用
[...参数]
定义文件名,将匹配地址栏输入的任意参数 - 当希望为相同的页面提供不同的 url 时,或者处理一些路由参数可选的页面时使用
pages/docs/[...params].js
1. - 访问
localhost:3000/docs
将跳转 404 页面 - 访问
localhost:3000/docs/feature1
- 访问
localhost:3000/docs/feature1/concept1
- 访问
localhost:3000/docs/feature1/concept1/example1
import { useRouter } from "next/router";
function Doc() {
const router = useRouter();
const { params = [] } = router.query;
if (params.length === 2) {
return (
<h1>
Viewing docs for feature {params[0]} and concept {params[1]}
</h1>
);
} else if (params.length === 1) {
return <h1>Viewing docs for feature {params[0]}</h1>;
}
return <h1>Docs Home Page</h1>;
}
export default Doc;
pages/docs/[[...params]].js
2. - 访问
localhost:3000/docs
将正常返回 Doc 页面
(八)Link Component Navigation —— Link 组件
- 组件
prop
可以收到动态路由参数 Link
组件默认使用push
跳转,使用replace
属性切换Link
组件跳转是客户端跳转,不会和a
标签一样重新请求服务器页面导致刷新
pages/index.js
1. import Link from "next/link";
function Home() {
return (
<div>
<h1>Home Page</h1>
<Link href="/blog">
<a>Blog</a>
</Link>
<br />
<Link href="/product">
<a>Products</a>
</Link>
</div>
);
}
export default Home;
pages/product/index.js
2. import Link from "next/link";
function ProductList({ productId = 100 }) {
return (
<>
<Link href="/">
<a>Home</a>
</Link>
<h2>
<Link href="/product/1">
<a>Products 1</a>
</Link>
</h2>
<h2>
<Link href="/product/2">
<a>Products 2</a>
</Link>
</h2>
<h2>
<Link href="/product/3" replace>
<a>Products 3</a>
</Link>
</h2>
<h2>
<Link href={`/product/${productId}`}>
<a>Products {productId}</a>
</Link>
</h2>
</>
);
}
export default ProductList;
(九)Navigating Programmatically —— 编程式路由导航
useRouter
钩子函数提供push
和replace
方法,以实现编程时路由跳转
pages/index.js
1. import Link from "next/link";
import { useRouter } from "next/router";
function Home() {
const router = useRouter();
const handleClick = () => {
console.log("Placing your order.");
// router.push("/product");
router.replace("/product");
};
return (
<div>
<h1>Home Page</h1>
<Link href="/blog">
<a>Blog</a>
</Link>
<br />
<Link href="/product">
<a>Products</a>
</Link>
<button onClick={handleClick}>Place Order</button>
</div>
);
}
export default Home;
(十)Custom 404 Page —— 自定义 404 页面
NextJS
默认提供了 404 页面(没有显示在目录中)- 在
pages
目录下创建404.js
文件会替换默认提供的 404 页面
pages/404.js
1. function PageNotFound() {
return <h1>404 Page with all the custom styling necessary.</h1>;
}
export default PageNotFound;