Next.js

2022-06-11  本文已影响0人  贪恋冬天的幸福

getStaticProps
技术细节:

export async function getStaticPaths() {
  return {
    paths: [
       { params: { ... } }
    ],
    fallback: true,   //false or 'blocking' 
  } 
}
  1. paths 属性是必须的
    paths 属性定义了哪些路径会被预渲染。例如,如果你有一个使用动态路由的页面 pages/posts/[id].js,如果你在这个页面中导出 getStaticPaths方法并且返回如下的 paths
return {
  paths: [
     { params: { id: '1' } },
     { params: { id: '2' } }
  ],
  fallback: ...
}

然后 Next.js 会在构建时使用这个页面组件静态生成 posts/1posts/2
注意 params 的值必须与页面中使用的参数对应:

  1. fallback 属性是必须的
    fallback: false
    如果 fallbackfalse,那么任何路径都不会生成并且变成一个404页面。你可以在你仅有少量的路径去预渲染的时候这样做,这样的话在构建时都是静态页面。当并不经常添加新的页面的时候这样做很有用。但是当你需要然后新的时候的时候,你就需要重新构建。
    这里有一个预渲染一个博客详情页面 pages/posts/[id].js 的示例,博客列表会从一个内容管理系统(CMS)中获取并且通过 getStaticPaths 返回。然后,每个详情页面,它通过 getStaticProps 从一个内容管理系统(CMS)获取数据。这里示例如下:
// pages/posts/[id].js

function Post({ post }) {
    //Render post...  
}

// This function gets called at build time
export async function getStaticPaths() {
  //Call an external API endpoint to get posts
  const res = await fetch('https://.../posts');
  const posts = await res.json()
  
   //Get the paths we want to pre-render based on posts
   const paths = posts.map((post) => ({
       params: { id: post.id },
   }))
   
    //We`ll pre-render only these paths at build time.
    // { fallback: false } means other routes should 404.
    return { paths, fallback: false }
}

//This also gets called at build time
export async function getStaticProps({ params }) {
  //params contains the post `id`.
  //if the route is like /posts/1, then params.id is 1
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()
  //Pass post data to the page via props
  return { props: { post } }
}

export default Post;

fallback: true
如果fallbacktrue,那么getStaticProps的行为会有如下变化:

注意:fallback: true 在使用 next export 时是不被支持的。

  1. 回退页面(fallback pages)
    在页面的回退版本:
//pages/posts/[id].js
import { useRouter } from 'next/router';

function Post({ post }) {
    const router = useRouter()
    //if the page is not yet generated, this will be displayed initially until 
    //getStaticProps() finishes running
    if (router.isFallback) {
       return <div>Loading...</div>    
     }
     // Render post...
}

// This function gets called at build time
export async function getStaticPaths() {
    return {
        //Only `/posts/1` and `/posts/2` are generated at build time
        paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
        //Enable statically generating additional pages
        //For example: `/posts/3`
        fallback: true,
    }
}

// This also gets called at build time
export async function getStaticProps({ params }) {
    //params contains the post `id`.
    //if the route is like /posts/1, then params.id is 1
    const res = await fetch(`https://.../posts/${params}.id`)
    const post = await res.json()
      
     //Pass post data to the page via props 
     return {
         props: { post },
         //Re-generate the post at most once per second
         //if a request comes in
         revalidate: 1,
     }
}

export default Post;
  1. fallback: true 何时最有用?
    当你的应用有大量的依赖于数据(depend on data)的静态页面 fallback: true ,你想要预渲染所有的商品页面,但这样你的构建将花费很长时间。取而代之的是,你可以静态生成一个很小的页面集合,其余部分通过使用 fallback: true 生成。当有用户请求一个还没有生成的页面时,用户会看到页面中有一个加载指示器。很快的,getStaticProps 执行完成,页面会根据请求到的数据渲染。之后同样请求此页面的任何用户将会得到静态预渲染的页面。
    这确保了用户在保持快速构建和静态生成的好处的同时始终拥有最快的体验。
    fallback: true 并不会更新已经生成的页面,具体可查看增量静态再生(Incremental Static Regeneration)。

  2. fallback: 'blocking'
    如果 fallbackblockinggetStaticPaths未返回的新路径将等待HTML完全生成,与 SSR 是完全相同的,然后被缓存下来以供将来的请求使用,因此每个路径只发生一次。
    getStaticProps会有如下行为:

当使用 next export 的时候 fallback: 'blocking' 是不支持的。

  1. 什么时候使用 getStaticPaths
    如果要静态预渲染使用动态路由的页面,则应使用getStaticPath。
  2. 使用 TypeScript:GetStaticPaths
    需要使用 TypeScript,可以引入 next 的 GetStaticPaths 类型;示例如下:
import { GetStaticPaths } from 'next'

export const getStaticPaths: GetStaticPaths = async () => {
  //...
}

技术细节:

  1. 结合 getStaicProps使用
    当你的页面中 getStaticProps 使用动态路由参数的时候,你必须使用 getStaticPaths。你不能结合 getServerSideProps 使用 getStaticPaths
  2. 只在构建时在服务端运行
  3. 只允许在页面中被使用
    getStaticPaths 只能被一个页面导出,不能在非页面文件导出。
    同时,你必须使用 export async function getStaticPaths() {} ,如果你将 getStaticPaths 设置为一个页面组件的属性将不会生效。
  4. 开发环境每次请求都会运行
    在开发环境(next dev),getStaticPaths 将会在每次请求时都执行。

getServerSideProps( 服务端渲染 Server-side Rendering)

当你从一个页面导出一个叫做 getServerSidePropsasync 函数 ,Next.js 将会使用通过 getServerSideProps 获取的数据在每次请求的时候预渲染这个页面。

export async function getServerSideProps(context) {
    return {
         props: {},  //will be passed to the page component as props
     }
}

context 参数是一个包含以下键的对象:

export async function getServerSideProps(context) {
    const res = await fetch(`https://...`);
    const data = await res.json()

    if (!data) {
        return {
             notFound: true,
         }
    }
    
     return {
         props: {}, // will be passed to the page component as props
     }
}
export aysnc function getServerSideProps(context) {
    const res = await fetch(`https://.../data`);
    const data = await res.json()
    
     if (!data) {
          return {
               redirect: {
                    destination: '/',
                    permanent: false,
               },
           }
      }
   
       return {
              props: {},  //will be passed to the page component as props
        }
}

注意:你可以导入顶级作用域中的模块,以便在 getServerSideProps 中使用。 getServerSideProps 中使用的导入不会为客户端绑定。这意味着你可以直接在 getServerSideProps 中编写服务器端代码。这包括从读写文件系统或数据库。
注意:你不应该在 getServerSideProps 中使用 fetch() 调用API路由。相反,直接导入API路由中使用的逻辑。对于这种方法,您可能需要稍微重构代码。从外部API获取是很棒的实践。

  1. 提供 req 中间件
    传递给 getServerSideProps 的上下文中的 req 提供了解析传入请求 (req)的内置中间件。该中间件是:
  1. 使用示例
    下面是一个使用 getServerSideProps 在请求时获取数据并预渲染的示例。
function Page({ data }) {
    //Render data...
}

//This gets called on every request
export async function getServerSideProps() {
    //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
  1. 何时应该使用?
    只有当需要预渲染一个必须在请求时获取数据的页面的时候使用 getServerSideProps 。第一个字节到达的时间(TTFB)将会比 getStaticProps 慢,因为服务端需要在每次请求时计算结果,并且如果没有额外的配置,CDN无法缓存结果。
    如果你不需要预渲染数据,你应该考虑在客户端请求数据。客户端获取数据参考这里
  2. 使用 TypeScript: GetServerSideProps
    需要使用类型定义(TypeScript),可以从next中引入GetServerSideProps,示例如下:
import { GetServerSideProps } from 'next'

export const getServerSideProps: GetServerSideProps = async (context) => {
      //...
}

如果你想为页面的 props 获取推断类型,可以使用 InferGetServerSidePropsType<typeof getServerSideProps>,示例如下:

import { InferGetServerSidePropsType } from 'next'

type Data = { ... }

export const getServerSideProps = async () => {
    const res = await fetch('https://.../data')
    const data: Data = await res.json()
    
    return {
       props: {
           data,
       }
    }
}

function Page({ data }: InferGetServerSidePropsType<typeof getServerSideProps>) {
    //will resolve posts to type Data
}

export default Page

技术细节:

上一篇下一篇

猜你喜欢

热点阅读