Next学习_基础知识

学习来源,内容简洁易懂,推荐大家学习

1. 简介

Next.js 是基于React框架,具有服务端渲染功能。它快速且对SEO友好。使用Next.js,我们可以非常轻松的创建健壮的基于React的应用并对其进行测试。

1.1 为什么选择Next.js

  • 零配置 - 自动编译并打包,从一开始就为生产环境而优化
  • 混合模式 - SSG和SSR 在一个项目同时支持构建时预渲染页面(SSG)和请求时渲染页面(SSR)
  • 增量静态生成 - 在构建之后以增量的方式添加并更新静态预渲染的页面
  • 支持TypeScript - 自动配置并编译TypeScript
  • 快速刷新 - 快速、可靠的实时编辑体验
  • 基于文件系统的路由 - 每个pages目录下的组件都是一条路由
  • API路由 - 创建API端点(可选)以提供后端功能
  • 支持内置CSS - 使用CSS模块创建组件级样式。内置对sass的支持
  • 代码拆分和打包 - 采用由Google Chrome小组创建的、并经过优化的打包和拆分算法

2. 快速开始

2.1 创建项目

  • npm init 项目初始化
  • npm install next react react-dom 安装依赖
  • package.json 的 scripts 字段中添加如下代码片段 配置next指令
      "dev": "next dev",
      "build": "next build",
      "start": "next start",
      "lint": "next lint"
    

2.2 Next指令解析

  • dev - 运行next dev,以开发模式启动Next.js
  • build - 运行next build,以构建用于生产环境的应用程序
  • start - 运行next start,以启动Next.js生产环境服务器
  • lint - 运行next lint,以设置Next.js的内置ESlint配置

3. 快速开发

Next.js 是围绕着页面(pages)的概念构造的。一个页面(page)就是从一个pages目录下的.js、.jsx、.ts或.tsx文件导出(export)的React组件。

  • 在next.js中创建一个pages目录,并创建一个包含以下内容的index.js文件
pages/index.js


function HomePage() {
  return <div><h1>Welcome your first Next</h1></div>
}

export default HomePage
  • 启动项目 npm run dev,就可以在页面上看到对应的内容啦

3. Next.js 页面

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

  • pages/index.js 与 ‘/’ 路由链接
  • pages/posts/first.js 与 ‘posts/first’ 路由相关联

页面间跳转,可以通过Link标签方式进行,通过href设置跳转地址,比如在其他页面中返回首页

pages/post/first.js

import Link from "next/link"; // 引入Link标签
function FirstPost() {
  return (
    <div>
      <h2>这是邮局的第一封信</h2>
      <Link href='/'> // 使用Link标签
        返回首页
      </Link>
    </div>
  )
}

export default FirstPost

4. 静态文件服务

Next.js支持静态文件(例如图片)存放在根目录public目录中,并对外提供访问。public目录下存放的静态文件对外访问路径以/作为起始路径。在Next.js中,页面是一个React组件,从pages目录中导出,每个页面根据其文件名与一个路由相关联。

  • 新建public文件件,并放入图片等静态文件信息
例如,在public/images/bz.jpg有一张图片,在页面中引用时:

<img src="/images/bz.jpg" alt=""/>

5. 元数据 (Meta Data)

在next.js中,我们可以借助内置的<Head> React组件非常轻松地修改每个React页面的head部分。

  • 引入Head标签
  • 使用Head标签,通过内置title属性设置页面title值

代码示例:

xxx.js

import Head from "next/head"; // 引入head标签

function FirstPost() {
  return (
    <div>
      <Head> // 页面中使用head
        <title>
          这是邮局的第一封信
        </title>
      </Head>
    </div>
  )
}

export default FirstPost

6. 对CSS的支持

在Next.js中,我们可以使用名为styled-jsx的内置css-in库。它允许在React组件中编写css,并且将这些样式作用于组件。

6.1 通过包裹子组件设置CSS

比如通过包含组件内容,来给组件设置一个公共的外壳样式container,这样在每个页面都可以用Container进行包裹,设置成对应的样式,比如设置PC端内容所占区域就可以使用该方式

  • 新建components文件夹
  • 在components文件夹中创建container.module.css, 用于设置样式
    .container {
        width: 1280px;
        min-height: calc(100vh - 48px);
        border: 1px solid cornflowerblue;
        border-radius: 48px;
        padding: 24px;
        margin: 0 auto;
    }
    
  • 在components文件夹中创建container.js,用于引用样式,并设置页面结构,如下示例则表示,给包裹在其中的页面内容设置container样式
    import styles from './container.module.css'
    
    function Container({children}) {
      return <div className={styles.container}>{children}</div>
    }
    
    export default Container
    
  • 在页面中进行使用,页面xxx.js,这样被Container包含的组件自然包含该样式
    import Link from "next/link";
    import Head from "next/head";
    import Container from "../components/container"; // 引用Container样式模块
    function HomePage() {
      return (
        <Container> // 使用Container样式模块
          <Head>
            <title>这是首页</title>
          </Head>
          <h1>Welcome your first Next</h1>
          <Link href='/post/first'>Post First</Link>
        </Container>
      )
    }
    
    export default HomePage
    

6.2 给具体位置设置不同的样式

例如,我们有一个first.js页面,想要给该页面的标题设置一个单独的样式

  • 在同等目录下,新建first.module.css文件
    .title_red {
        color: #6C3838FF;
    }
    
  • 在页面中引用该样式表
    import First from './first.module.css'
    
    <h2 className={First.title_red}>这是邮局的第一封信</h2>
    

6.3 全局内置CSS样式

  • 定义全局样式表 styles/styles.css
    html,
    body {
        padding: 0;
        margin: 0;
        line-height: 1.6;
        font-size: 18px;
        background-color: lime;
    }
    
    * {
        box-sizing: border-box;
    }
    
    a {
        color: #0070f3;
        text-decoration: none;
    }
    
    a:hover {
        text-decoration: underline;
    }
    
    img {
        max-width: 100%;
        display: block;
    }
    
  • 定义全局文件,应用全局样式 pages/_app.js
import '../styles/styles.css'

export default function App({Component, pageProps}){
  return <Component {...pageProps} />
}

7. 预渲染

在Next.js中,我们知道它会为称为预渲染的页面生成HTML。Next.js中支持两种类型的预渲染:

  • 静态生成 - 此方法在构建时生成HTML页面。这个预渲染的HTML在每个请求上面发送。这种方法对于营销网站、博客、电子商务产品列表网站、帮助、文档网站很有用
  • 服务器端生成 - 此方法在每个请求上生成HTML页面。此方法适用于HTML页面内容可能随着某个请求而变化的情况

7.1 每个页面预渲染

Next.js允许为每个页面设置预渲染方法,其中大部分遵循静态生成,其他页面使用服务端渲染

7.2 无数据静态生成

静态生成可以在没有数据的情况下完成,在这种情况下,HTML页面将准备就绪,无需预取数据然后开始渲染。可以稍后或根据请求获取数据。这种技术有助于在没有任何数据的情况下向用户显示用户界面,以防获取数据需要一定的时间。

7.3 使用数据进行静态生成

静态生成可以用数据完成,在这种情况下,HTML页面在获取数据之前不会准备好,因为HTML可能会依赖于数据。每个组件都有一个特殊的方法getStaticProps可以用来获取数据并将数据作为页面的props传递,以便页面可以根据传递的props进行渲染。getStaticProps()函数在生产中的构建时运行,并在开发模式下每个请求都会运行

  • 在获取请求数据时,根目录 pages/index.js 使用 getServerSideProps方法,其他页面pages/xxx/sss.js使用getStaticProps方法

pages/index.js中使用getServerSideProps

import Link from "next/link";
import Head from "next/head";
import Container from "../components/container";
function HomePage(props) {
  return (
    <Container>
      <Head>
        <title>这是首页</title>
      </Head>
      <h1>下面是应季水果清单:</h1>
      <Link href='/post/first'>Post First</Link>
      <ul>
        {props.list.map((item, index) => (
          <li key={index}>{item.fruitsname}</li>
        ))}
      </ul>
    </Container>
  )
}
export async function getServerSideProps() { // 使用该方法发起网络请求,并将请求返回数据赋值给props
  const res = await fetch('http://localhost:8090/api/fruits')
  const resJson = await res.json()

  return {
    props: {
      list: resJson.dataSource
    }
  }
}

export default HomePage

pages/xxx/sss.js中使用getStaticProps

import Link from "next/link";
import Head from "next/head";
import Container from "../../components/container";
import First from './first.module.css'
function FirstPost(props) {
  return (
    <Container>
      <Head>
        <title>
          这是邮局的第一封信
        </title>
      </Head>
      <h2 className={First.title_red}>这是邮局的第一封信</h2>
      <Link href='/'>
        返回首页
      </Link>
      ||
      <a href="https://www.baidu.com" target='_blank'>跳转外部的链接</a>
      <ul>
        {props.list.map((item, index) => {
          return <li key={index}>{index}{item.fruitsname}</li>
        })}
      </ul>
    </Container>
  )
}
export async function getStaticProps() { // 使用该方法获取网络请求数据
  const res = await fetch('http://localhost:8090/api/fruits')
  const resJson = await res.json()

  return { // 将从网络请求获取到的数据赋值给props的list列表
    props: {
      list: resJson.dataSource
    }
  }
}

export default FirstPost

8. 路由

8.1 路由信息汇总

Next.js使用基于文件系统的路由器,每当我们将任何页面添加到pages目录时,它都会自动通过url获得

  • index routes 文件夹中存在的index.js文件映射到目录的根目录

    • pages/index.js 映射到 ‘/’
    • pages/posts/index.js 映射到 ‘pages/posts’
  • nested routes 路由器支持嵌套路由,如果您创建嵌套文件夹结构,文件将自动以相同的结构定义路由

    • pages/settings/dashboard/about.js 映射到“/settings/dashboard/about”
    • pages/posts/first.js 映射到“/posts/first”
  • dynamic routes 我们也可以使用命名参数来匹配url

    • pages/posts/[id].js 映射到“/posts/:id”,我们可以在其中使用“/posts/1”之类的 URL
    • pages/[user]/settings.js 映射到“/posts/:user/settings”,我们可以在其中使用“/abc/settings”之类的 URL
    • pages/posts/[…all].js 映射到“/posts/*”,我们可以在其中使用任何 URL,例如“/posts/2020/jun/”

8.2 动态路由

我们可以在首页定义一个list列表数据展示 pages/index.js

import Link from "next/link";
import Container from "../components/container";
function HomePage(props) {
  return (
    <Container>
      <h1>下面是应季水果清单:</h1>
      <Link href='/post/first'>Post First</Link>
      <ul>
        {props.list.map((item, index) => (
          <li key={item.id}>
            <Link href={`/fruits/${item.id}`}>{item.fruitsname}</Link>
          </li>
        ))}
      </ul>
    </Container>
  )
}
export async function getServerSideProps() {
  const res = await fetch('http://localhost:8090/api/fruits')
  const resJson = await res.json()

  return {
    props: {
      list: resJson.dataSource
    }
  }
}

export default HomePage

跳转至详情页面后,定义对应的pages/fruits/[id].js,使用useRouter获取当前页面路由信息

import {useRouter} from "next/router";
function FruitPage() {
  const router = useRouter()
  return (
    <>
      <h3>这是水果{router?.query?.id}详情页面</h3>
    </>
  )
}
export default FruitPage

8.3 命令式路由

之前我们都是通过Link组件配置路径在页面上点击完成路由的跳转功能,还有另一种非HTML方式可以来实现这种功能——useRouter

import {useRouter} from "next/router";
function HomePage(props) {
  const router = useRouter() // 在函数组件中获取router实例
  function toPostPage() {
    router.push('/post/first') // 通过router.push跳转至新的页面
  }

  return (
    <Container>
      <button style={{width: '200px',height: '48px'}} onClick={toPostPage}>点击跳转至Post</button>
    </Container>
  )
}

8.4 浅层路由

在 Next.js 中,浅层路由允许我们更改 URL 而无需再次运行数据获取方法,包括 getServerSideProps、getStaticProps 和 getInitialProps。要启用浅层路由,需要将 shallow 选项设置为 true。

  • 例如,当我们在首页/,想要访问带有query参数的首页/?count=23,此时我们设置了shallow选项为true,那么跳转后,不会再次发起网络请求,可以根据网络请求出console打印的内容即可了解调用的结果
import Container from "../components/container";
import {useRouter} from "next/router";
function HomePage(props) {
  const router = useRouter()
  
  function toCurpageQuery() {
    router.push('/?count=65', undefined, {shallow: true})
  }

  return (
    <Container>
      <button onClick={toCurpageQuery}>跳转至当前页面,增加query参数</button>
    </Container>
  )
}
export async function getServerSideProps() {
  const res = await fetch('http://localhost:8090/api/fruits')
  const resJson = await res.json()
  console.log('调用index的接口')

  return {
    props: {
      list: resJson.dataSource
    }
  }
}

export default HomePage

9. Next Api路由

API路由(API routes)是一种使用Next.js创建REST API的方法。Next.js映射/pages/api文件夹中存在的任何文件,并将其视为api端点。API函数示例

export default (req, res) => {
	...
}
  • req - req 是 http.IncomingMessage 的一个实例,用于从请求中获取数据
  • res - res 是 http.ServerResponse 的一个实例,用于发送数据作为相应

下面是一个简单的api设置方式

  • 将api文件夹设置在pages目录下
  • api文件夹中可以创建各种文件,例如:hobby.js
export default (req, res) => {
  res.statusCode = 200
  res.setHeader('Content-type', 'application/json')
  res.end(JSON.stringify({slogan: '我爱篮球'}))  // 使用JSON.stringify,不然网页识别有问题
}

此时,运行项目,访问地址http://localhost:3000/api/hobby,即可看到我们所设置的api数据

9.1 中间件

Next.js为API路由提供了内置的中间件,用于解析传入的请求(req)。这些中间件是:

  • req.cookie - 包含请求发送的cookie对象。默认为 {}
  • req.query - 包含查询字符串的对象。默认为 {}
  • req.body - 包含由content-type解析的正文的对象,如果没有发送正文,则为null

我们可以将上面的简单示例进行变形:

export default (req, res) => {
  res.statusCode = 200
  res.setHeader('Content-type', 'application/json')
  res.end(JSON.stringify({query: req.query}))
}

此时访问: http://localhost:3000/api/hobby?counter=23,就会看到页面打印的内容是{"query":{"counter":"23"}}

9.2 响应辅助办法 Response Helpers

res对象具有express.js之类的辅助办法,以简化开发来创建服务

  • res.status(code) - 此方法设置响应的状态,传递的代码必须是有效的
  • res.json(json) - 此方法返回json响应,传递的json对象必须是有效的json对象

使用示例:

export default (req, res) => {
  res.status(200).json({slogan: '\'完蛋啦,页面没找到,下班吧\''})
}

注意事项:

  • 动态路由处,next动态页面[id]方式命名文件,nuxt使用_id方式命名文件
  • 在定义模板标签内容时,vue使用{{}},react使用{},react在内联样式style标签中设置样式时使用{{}}
  • 无论是http://localhost:3000/fruits/1这种参数的1,还是http://localhost:3000/?count=65这种参数的65,都在router中的query参数中,通过具体的id或者count来获取,不区分params和query

如果有用,点个赞呗~

总结用法,希望可以帮助到你,
我是Ably,你无须超越谁,只要超越昨天的自己就好~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值