nextjs系列教程(三):pages和路由

Pages页面用法

1.1 概念介绍

在 Next.js 中,一个 page(页面) 就是一个从 .js、jsx、.ts 或 .tsx 文件导出(export)的 React 组件 ,这些文件存放在 pages 目录下。每个 page(页面)都使用其文件名作为路由(route)。

1.2 创建page页面

  1. 如果你创建了一个命名为 pages/about.jsx 的文件并导出(export)一个如下所示的 React 组件,则可以通过 /about 路径进行访问。
    	function About() {
    	  return <div>About</div>
    	}
    	export default About
    
  2. 如果你创建了一个命名为 pages/home/index.jsx 的文件并导出(export)一个如下所示的 React 组件,则可以通过 /home 路径进行访问。
    function Home() {
      return <div>Home</div>
    }
    export default Home
    
  3. 注意:项目启动时默认加载的首页页面冲突问题:

    src/app/page.jsx 默认首页文件存在的时候,此页面将作为 http://localhost:3000 的默认启动页面。如果此时在 pages 目录下又新建了 index.jsx 页面,就会和 src/app/page.jsx 中的页面产生冲突,导致首页无法正常加载。因此,两者只存在一个即可,另外一个相关文件要删除。

1.3 路由分类

  1. Index routes:索引路由

    路由将自动跳转到 pages 目录下名为 index 的路由文件。

    比如:

    pages/index.jsx → /
    pages/blog/index.jsx → /blog
    
  2. Nested routes:嵌套目录路由

    路由器支持嵌套文件。如果创建嵌套文件夹结构,文件仍将以相同的方式自动路由。

    比如:

    pages/blog/first-post.js → /blog/first-post
    pages/dashboard/settings/username.js → /dashboard/settings/username
    
  3. Dynamic route segments:动态参数路由

    使用 [] 括号语法,可以进行动态路由参数的匹配。

    比如:

    pages/blog/[slug].js → /blog/:slug (/blog/hello-world)
    pages/[username]/settings.js → /:username/settings (/foo/settings)
    pages/post/[...all].js → /post/* (/post/2020/id/title)
    

1.4 声明式路由跳转页面

  1. 介绍

    Next.js路由器允许您在页面之间进行客户端路由转换,类似于单页面应用程序。

  2. 修改 src/app/page.jsx 默认页面,通过字符串方式配置路由页面的跳转链接:

    import Link from "next/link";
    
    function App() {
      return (
        <ul>
          <li>
            <Link href="/home">主页</Link>
          </li>
          <li>
            <Link href="/profile">个人中心</Link>
          </li>
        </ul>
      );
    }
    
    export default App;
    
    • 上面的 ul 使用了多个 href 链接。每一个(href)都映射到一个已知页面组件:
    /home → pages/home/index.jsx
    /profile → pages/profile/index.jsx
    
  3. 通过url对象方式配置路由跳转:

    <li>
        <Link href={{ pathname: "/home/[动态路由]", query: { a: 100 } }}>主页</Link>
     </li>
    
  4. 重定向路由实现页面跳转:

    Link 组件默认将 url 推入路由栈中,生成一个路由跳转历史记录。你可以使用replace属性来重定向路由,防止生成路由历史记录。

    <li>
        <Link replace href={{ pathname: "/home", query: { a: 100 } }}>
          主页
        </Link>
     </li>
    
  5. Link组件下的children只能是单独的一个,而不能是多个子节点:

    <Link href='/a'>
    	<Fragment>
    		<button>按钮</button>
    		<button>按钮</button>
    	</Fragment>
    </Link>
    
  6. <Link /> 组件API汇总:

    • href - 导航的目标路径或 URL,这是唯一一个必须设置的属性;
    • as - 可选的路径装饰符,用于改变显示在浏览器地址栏中的URL格式。如果你在服务器端设置了自定义路由as将会起作用,否则页面切换会出现404情况;
      • as 路由映射是指:比如有一个路由是 /post?id=2&articleId=199,这样的路由看起来是不友好的。我们想要在浏览器地址栏中看到 /post/2/199,这样的路径。从前种方法到后种方法之间的转换就叫做路由映射。
      • 使用 next 中的 <Link /> 组件提供的as属性,就可以实现路由格式的转换。
      • as 是浏览器地址栏显示的path,并不是真正的path;而href才是真正的跳转路径。as只是改变了以下路由的外观,本质还是href。

1.5 编程式路由跳转页面

  1. 介绍

    除了使用声明式路由,还可以用 next/router 或者 next/navigation 的编程式路由API实现客户端路由切换。

  2. src/app/page.jsx 首页页面如果要配置编程式API进行路由跳转,需要使用:next/navigation 搭配 "use client" 才可以正确使用useRouter,因为 app/page.jsx 页面默认属于服务端组件了,而不是客户端组件。

    "use client"; // 必须要添加
    import Link from "next/link";
    import { useRouter } from "next/navigation";
    
    function App() {
      const router = useRouter();
      return (
        <div>
          <button
            onClick={() => {
              router.push("/home");
            }}
          >
            主页
          </button>
        </div>
      );
    }
    export default App;
    
  3. 如果 src/app/page.jsx 使用 next/router 则会报如下错误:

    You have a Server Component that imports next/router. Use next/navigation instead.
    Maybe one of these should be marked as a client entry "use client":
    	./src\app\page.jsx
    
  4. 如果是非 src/app/page.jsx 页面的其它路由组件,配置编程式导航,则使用 next/router,比如:src/pages/home/index.jsx 页面:

    import { useRouter } from "next/router";
    export default function Home() {
      const router = useRouter();
      return (
        <div className="Home">
          <h4>首页</h4>
          <button
            onClick={() => {
              router.back();
            }}
          >
            返回
          </button>
        </div>
      );
    }
    
  5. const router = useRouter() 返回的router对象API汇总:

    • router.push(url, as, options):进入某个路由;第二个参数as,是为了装饰 URL ,如果你在服务器端设置了自定义路由将会起作用。
    • router.replace(url, as, options):重定向路由;
    • router.back():返回上一个路由;
    • router.reload():重载当前路由;
    • router.prefetch(url, as):预读取某个路由的组件内容;仅在生产环境下有效;
    • router.beforePopState(cb):在路由器处理事件之前拦截

1.6 路由页面的预读取prefetch

  1. 介绍

    Next.js 一个非常实用的功能就是你在浏览当前页面的时候,Next.js 会自动 prefetch 页面上所有的站内链接页面。这样一来,当你真正点击某个链接时,就可以迅速加载该页面,快得简直就像是在读取本地文件。
    可能这就是为什么同样是 client-side navigation(客户端导航),Next.js 要比常规的 React SPA 的页面跳转快这么多吧!

  2. 这个功能在 <Link /> 中是默认开启的。除非像下面这样把 <Link> 的 prefetch 置为 false,Next.js 就不会在当前页面,再去 prefetch 该路由:

    <Link href="/home" prefetch={false}>
      <a>主页</a>
    </Link>
    

    prefetch 属性会在后台预读取目标路由页面,默认值为 true。它具有以下特性:

    1. 处于视口(viewport)中(初始或滚动后)的任何 <Link /> 都将被预加载。通过设置 prefetch={false} 可以禁止页面预取。
    2. 当 prefetch 被设置为 false 时,鼠标悬停在 <Link /> 上时仍然会触发预取。
    3. 使用 静态生成 的页面(pages)将预加载存有数据的 JSON 文件,以实现更快的页面切换。
    4. 预取功能只在生产环境中开启。
  3. router.prefetch(url, as, options) 编程式API进行页面预读取:

    // 假设您有一个登录页面,登录后,您将用户重定向到仪表板。
    // 对于这种情况,我们可以预取仪表板以进行更快的转换,如以下示例所示:
    import { useCallback, useEffect } from 'react'
    import { useRouter } from 'next/router'
    
    export default function Login() {
      const router = useRouter()
      const handleSubmit = useCallback((e) => {
        e.preventDefault()
        fetch('/api/login', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({}),
        }).then((res) => {
          if (res.ok) router.push('/dashboard')
        })
      }, [])
    
      useEffect(() => {
        // 预读取 /dashboard 页面
        router.prefetch('/dashboard')
      }, [router])
    
      return (
        <form onSubmit={handleSubmit}>
          <button type="submit">Login</button>
        </form>
      )
    }
    
  4. prefetch 的内容是如何存储的?

    通过 <link rel="prefetch"> 的方式,浏览器会请求相应的 .js 和 .css 文件,但不会执行它们,而是作为缓存把它们储存在浏览器中。等到用户真正跳转到该 route,需要加载这些文件时,就可以直接从本地加载,不需要请求服务器了,其实也是一种前端提高性能的常见方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值