Nextjs

Posted by lanbery on October 21, 2021

Nextjs

Nextjs folder structure

ROOT PATH DESC COMMENTS
base_dir 项目跟目录
──┰─ pages 默认页面路由使用
──┝─ public 默认进行静态文件输出

routes

路由部分Next.js做了简化,默认是使用文件夹的形式,在base_dir/pages/name.js|tsx下的文件,会映射为your_site/name这个路径

Dynamic Routes

上述的路由不能很好支持your_site/user/:user_id这样的需求。类似这样的需求在Next.js中也有解决方案,我们可以通过动态路由解决

我们只需要把page 文件名定义成 /pages/user/[uid]/[user].js

SSR VS Static

Next.js默认支持了服务端渲染等提升前端获取速度和渲染性能的功能,但这也要求开发者必须谨慎对待组件的初始化和生命周期,因为显然运行在服务端和客户端的代码在获取组件初始化需要的数据时的方法是不一样的

如果一个Page里getServerSideProps或getInitialProps存在的话,该Page就会被识别为服务端渲染(SSR),会在每次请求的时候进行渲染。而如果这两者皆不存在的话,该页面就会在服务器启动并构建的时候生成静态页面,后续每次请求的时候都会直接返回该静态页面。此外,在DEV模式的情况下,即便是静态渲染的Page也会在每次请求的时候触发渲染,需要注意。

主要方法有以下几个:

  • getStaticPaths :这个方法一般是配合dynamic route进行使用,会在Next.js服务器启动,并进行服务器静态构建的时候运行。其作用是告诉后续的getStaticProps某个动态路径的可能项。如果这个page你不需要静态构建,或者这个page也不是dynamic route,那就不需要实现这个函数

例如: pages/user/[id].js中 getStaticPaths 需要返回:

export async function getStaticPaths() {
  return {
    paths: [
      { params: { id: '1' } },
      { params: { id: '2' } }
    ],
    fallback: true or false
  };
}

paths和fallback都是必须的键。fallback的意思是,当遇到客户端访问到一个并不存在于启动构建时制作的paths列表里的路径,Next.js应该允许客户端继续访问,还是直接返回一个404。这里要注意,如果fallback为true,也就是允许客户端继续访问的话,page代码一定要做好容错性,否则很容易导致页面报错

  • getStaticProps : 这个方法也是在Next.js服务器启动的时候,进行服务器静态构建的时候运行。其作用是用来给静态生成的页面提供props。同样的,如果这个page你不需要静态构建,那就不需要实现这个函数
export async function getStaticProps(context) {
  return {
    props: {}, // will be passed to the page component as props
  }
}

如果是dynamic route的情况,该函数的context会包含getStaticPaths提供的路径信息:context.params = { id: ‘1’ }。

  • getServerSideProps: 基本上已弃用,如果是静态生成页面的话,使用getStaticProps;如果是服务端渲染的话,使用getServerSideProps。如果仅只是客户端渲染的页面,则使用React的effect就可以了

变量配置

Next.js默认直接支持环境变量配置。基本上有配置相关需求就直接使用这个解决方案就OK了

Environment Variables

API 后端

之前提到的route都是pages下的页面,一般来说还需要前后端交互使用的/api/*,这个在Next.js中被称为 API Routes


自定义 App

创建pages/_app.js代码文件,就可以在里面进行一些应用级别的初始化工作。官方文档:Custom App。自定义App的可能需求为

  • Persisting layout between page changes
  • Keeping state when navigating pages
  • Custom error handling using componentDidCatch
  • Inject additional data into pages
  • Add global CSS

可能的应用场景:准备全局变量。在一款WEB应用中,某些数据是所有的页面都会有需求的,比如说当前session的最基本用户信息和权限信息等。而_app是所有的页面的基本入口,每个页面的渲染都会先经过它,那么其实就可以在这个代码中做这些事情。

页面渲染的先后顺序:

// Resolution order
//
// On the server:
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. document.getInitialProps
// 4. app.render
// 5. page.render
// 6. document.render
//
// On the server with error:
// 1. document.getInitialProps
// 2. app.render
// 3. page.render
// 4. document.render
//
// On the client
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. app.render
// 4. page.render
// _app.tsx
import App, {AppContext} from "next/app";

export type AppPageProps = AppProps & {
  your_global_page_props: any;
};

MyApp.getInitialProps = async (appCtx: AppContext) => {
    const appProps = await App.getInitialProps(appCtx);
    appProps.pageProps = {
        your_global_page_props: "",
    } as AppPageProps;

    return {...appProps};
};

// yourpage.tsx
import {AppPageProps} from "../_app";

export type YourPageProps = AppPageProps & {};

export default function YourPage(props: YourPageProps) {
    console.log(props); // { your_global_page_props: "" }
}

自定义Document

创建pages/_document.js代码文件,就可以在里面改动全局的<html>和<body>。

自定义服务器

在大部分情况下,使用next [start]命令启动的服务器就已经足够满足需求了,但某些时候,我们仍旧有需求需要自定义一些服务端的功能,这时候就需要改造Next.js自带的服务端功能了。


React

Effect

React的官方文档在:Using the Effect Hook - React。只要是涉及到状态变化的,都属于effect的范畴。一个React组件里可以使用useEffect函数注册多个effect事件。第二个参数的指定可以决定该effect事件应该在什么时候触发

[],效果同componentDidMount,仅只在组件mount的时候触发一次。同时,在这种effect中提供一个回调函数返回,则等同于componentWillUnmount,这个回调函数会在组件被unmount的时候被触发,用来做析构。

useEffect(() => {
  // your effect here
  return () => {}; // unmount
}, []);

无参数,效果同componentDidUpdate,每次组件re-render都会触发

useEffect(() => {
  // your effect here
}, [foo]);

[foo],在数组中放入prop或state,则该effect只会在这个prop或state发生变化的时候触发。这个数组里可以放入复数的变量,表示监听多个变量的变化,任何一个发生变化都会触发该effect。