Next.js简单使用教程

9,741 阅读6分钟

简介

Next.js 是一个轻量级的 React 服务端渲染应用框架。

官网链接:www.nextjs.cn/

优点:

  • 零配置

    自动编译并打包。从一开始就为生产环境而优化。

  • 混合模式: SSG 和 SSR

    在一个项目中同时支持构建时预渲染页面(SSG)和请求时渲染页面(SSR)

  • 增量静态生成

    在构建之后以增量的方式添加并更新静态预渲染的页面。

  • 支持 TypeScript

    自动配置并编译 TypeScript。

  • 快速刷新

    快速、可靠的实时编辑体验,已在 Facebook 级别的应用上规模上得到验证。

  • 基于文件系统的路由

    每个 pages 目录下的组件都是一条路由。

  • API 路由

    创建 API 端点(可选)以提供后端功能。

  • 内置支持CSS

    使用 CSS 模块创建组件级的样式。内置对 Sass 的支持。

  • 代码拆分和打包

    采用由 Google Chrome 小组创建的、并经过优化的打包和拆分算法。

创建Next.js项目

手动创建Next.js项目

mkdir nextDemo //创建项目

npm init //初始化项目

npm i react react-dom next --save //添加依赖

package.json中添加快捷键命令

 "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev" : "next" ,
    "build" : " next build",
    "start" : "next start"
  },

创建pages文件夹和文件

在项目根目录创建pages文件夹并在pages文件夹中创建index.js文件

function Index(){
    return (
        <div>Hello Next.js</div>
    )
}
export default Index

运行项目

npm run dev

creact-next-app快速创建项目

create-next-app可以快速的创建Next.js项目,它就是一个脚手架。

npm install -g create-next-app //全局安装脚手架

create-next-app nextDemo //基于脚手架创建项目

cd nextDemo

npm run dev //运行项目

目录结构介绍:

  • components文件夹: 这里是专门放置自己写的组件的,这里的组件不包括页面,指公用的或者有专门用途的组件。
  • node_modules文件夹:Next项目的所有依赖包都在这里,一般我们不会修改和编辑这里的内容。
  • pages文件夹:这里是放置页面的,这里边的内容会自动生成路由,并在服务器端渲染,渲染好后进行数据同步。
  • static文件夹: 这个是静态文件夹,比如项目需要的图片、图标和静态资源都可以放到这里。
  • .gitignore文件: 这个主要是控制git提交和上传文件的,简称就是忽略提交。
  • package.json文件:定义了项目所需要的文件和项目的配置信息(名称、版本和许可证),最主要的是使用npm install 就可以下载项目所需要的所有包。

Pages

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

如果你创建了一个命名为 pages/about.js 的文件并导出(export)一个如下所示的 React 组件,则可以通过 /about 路径进行访问。

路由

页面跳转一般有两种形式,第一种是利用标签<Link>,第二种是用js编程的方式进行跳转,也就是利用Router组件

Link

import React from 'react'
import Link from 'next/link'


const Home = () => (
  <>
    <div>我是首页</div>
    <div><Link href="/pageA"><a>去A页面</a></Link></div>
    <div><Link href="/pageB"><a>去B页面</a></Link></div>

  </>
)

export default Home

注意:用<Link>标签进行跳转是非常容易的,但是又一个小坑需要你注意一下,就是他不支持兄弟标签并列的情况。

 //错误写法
 <div>
  <Link href="/pageA">
    <span>去A页面</span>
    <span>前端博客</span>
  </Link>
</div>

//正确写法
<Link href="/pageA">
  <a>
    <span>去A页面</span>
    <span>前端博客</span>
  </a>
</Link>

Router

import Router from 'next/router'

<button onClick={()=>{Router.push('/pageA')}}>去A页面</button>

参数传递与接收

Next.js中只能通过通过query(?id=1)来传递参数,而不能通过(path:id)的形式传递参数。

import Link from 'next/link'

//传递
<Link href="/blogDetail?bid=23"><a>{blog.title}</a></Link>

    
    
//blog.js
import { withRouter} from 'next/router'
import Link from 'next/link'

const BlogDetail = ({router})=>{
    return (
        <>
            <div>blog id: {router.query.name}</div>
            <Link href="/"><a>返回首页</a></Link>
        </>
    )
}
//withRouter是Next.js框架的高级组件,用来处理路由用的
export default withRouter(BlogDetail)


/************************************************************************************/
import Router from 'next/router'

<button onClick={gotoBlogDetail} >博客详情</button>

function gotoBlogDetail(){
    Router.push('/blogDetail?bid=23')
}

//object 形式
function gotoBlogDetail(){
    Router.push({
        pathname:"/blogDetail",
        query:{
            bid:23
        }
    })
}

<Link href={{pathname:'/blogDetail',query:{bid:23}}><a>博客详情</a></Link>

动态路由

pages/post/[pid].js
route : /post/abc  -->  query : { "pid": "abc" }


pages/post/[pid]/[comment].js
route : /post/abc/a-comment  -->  query : { "pid": "abc", "comment": "a-comment" }


钩子事件

利用钩子事件是可以作很多事情的,比如转换时的加载动画,关掉页面的一些资源计数器.....

//路由发生变化时
Router.events.on('routeChangeStart',(...args)=>{
    console.log('1.routeChangeStart->路由开始变化,参数为:',...args)
})

//路由结束变化时
Router.events.on('routeChangeComplete',(...args)=>{
    console.log('routeChangeComplete->路由结束变化,参数为:',...args)
})

//浏览器 history触发前
Router.events.on('beforeHistoryChange',(...args)=>{
    console.log('3,beforeHistoryChange->在改变浏览器 history之前触发,参数为:',...args)
})

//路由跳转发生错误时
Router.events.on('routeChangeError',(...args)=>{
    console.log('4,routeChangeError->跳转发生错误,参数为:',...args)
})

/****************************hash路由***********************************/

Router.events.on('hashChangeStart',(...args)=>{
    console.log('5,hashChangeStart->hash跳转开始时执行,参数为:',...args)
})

Router.events.on('hashChangeComplete',(...args)=>{
    console.log('6,hashChangeComplete->hash跳转完成时,参数为:',...args)
})

获取数据

getStaticProps

构建时请求数据

在build阶段将页面构建成静态的html文件,这样线上直接访问HTML文件,性能极高。

  • 使用getStaticProps方法在build阶段返回页面所需的数据。
  • 如果是动态路由的页面,使用getStaticPaths方法来返回所有的路由参数,以及是否需要回落机制。
// posts will be populated at build time by getStaticProps()
function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

// This function gets called at build time on server-side.
// It won't be called on client-side, so you can even do
// direct database queries. See the "Technical details" section.
export async function getStaticProps(context) {
  // Call an external API endpoint to get posts.
  // You can use any data fetching library
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // By returning { props: { posts } }, the Blog component
  // will receive `posts` as a prop at build time
  return {
    props: {
      posts,
    },
  }
}

export default Blog

getServerSideProps

每次访问时请求数据

页面中export一个asyncgetServerSideProps方法,next就会在每次请求时候在服务端调用这个方法。

  • 方法只会在服务端运行,每次请求都运行一边getServerSideProps方法
  • 如果页面通过浏览器端Link组件导航而来,Next会向服务端发一个请求,然后在服务端运行getServerSideProps方法,然后返回JSON到浏览器。
function Page({ data }) {
  // Render data...
}

// This gets called on every request
export async function getServerSideProps(context) {
  // Fetch data from external API
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  // Pass data to the page via props
  return { props: { data } }
}

export default Page

CSS支持

添加全局样式表

要将样式表添加到您的应用程序中,请在 pages/_app.js 文件中导入(import)CSS 文件。

在生产环境中,所有 CSS 文件将自动合并为一个经过精简的 .css 文件。

你应该 只在 pages/_app.js 文件中导入(import)样式表

从 Next.js 9.5.4 版本开始,你可以在应用程序中的任何位置从 node_modules 目录导入(import) CSS 文件了。

对于导入第三方组件所需的 CSS,可以在组件中进行。

添加组件级CSS

  • [name].module.css

    //login.module.css
    .loginDiv{
        color: red;
    }
    
    //修改第三方样式
    .loginDiv :global(.active){
        color:rgb(30, 144, 255) !important;
    }
    
    import styles from './login.module.css'
    
    <div className={styles.loginDiv}/>
    
    

    Next.js 允许你导入(import)具有 .scss.sass 扩展名的 Sass 文件。 你可以通过 CSS 模块以及 .module.scss.module.sass 扩展名来使用组件及的 Sass

    npm i sass --save

    如果要配置 Sass 编译器,可以使用 next.config.js 文件中的 sassOptions 参数进行配置。

    const path = require('path')
    
    module.exports = {
      sassOptions: {
        includePaths: [path.join(__dirname, 'styles')],
      },
    }
    
  • CSS-in-JS

    可以使用任何现有的 CSS-in-JS 解决方案。 最简单的一种是内联样式:

    <p style={{ color: 'red' }}>hi there</p>
    

    使用 styled-jsx 的组件就像这样

    function HelloWorld() {
      return (
        <div>
          Hello world
          <p>scoped!</p>
          <style jsx>{`
            p {
              color: blue;
            }
            div {
              background: red;
            }
            @media (max-width: 600px) {
              div {
                background: blue;
              }
            }
          `}</style>
          <style global jsx>{`
            body {
              background: black;
            }
          `}</style>
        </div>
      )
    }
    
    export default HelloWorld
    

自定义Header

<Head>
    <title>技术胖是最胖的!</title>
    <meta charSet='utf-8' />
</Head>