Next.js 的三种渲染方式(BSR、SSG、SSR)

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

它支持三种渲染方式包括

  • 客户端渲染 BSR (Broswer Side Render)
  • 静态页面生成 SSG (Static Site Generation)
  • 服务端渲染 SSR (Server Side Render)

旧瓶装新酒

上面说的几种渲染方式,其实并非什么新东西,其实可以和这些技术对应起来

  • BSR — 用 JS、Vue、React 创建 HTML
  • SSG — 页面静态化,把 PHP 提前渲染成 HTML
  • SSR — PHP、Python、Ruby、Java 后台的基本功能

不同点

Next.js 的预渲染可以与前端 React 无缝对接


下面,以一个文章列表页面作为例子,分别解析一下三种渲染方式吧

客户端渲染

客户端渲染,顾名思义就是只在浏览器上执行的渲染,通过Vue 和 React 构建的单页面应用SPA 都是采用这种方式渲染

缺点

1 .白屏,在 AJAX 得到渲染之前,页面中并没有内容,只能通过 Loading 来过度

2. SEO 不友好,因为搜索引擎访问页面, 默认不会执行 JS,只能看到 HTML,而不会等待 AJAX 异步请求数据,所以搜索不到页面内容

代码

import {NextPage} from 'next';
import axios from 'axios';
import {useEffect, useState} from "react";
import * as React from "react";

type Post = {
    id: string,
    id: string,
    title: string
}
const PostsIndex: NextPage = () => {
    // [] 表示只在第一次渲染的时候请求
    const [posts, setPosts] = useState<Post[]>([]);
    const [isLoading, setIsLoading] = useState(false);
    useEffect(() => {
        setIsLoading(true);
        // 使用 AJAX 异步请求数据
        axios.get('/api/posts').then(response => {
          setPosts(response.data);
          setIsLoading(false);
        }, () => {
            setIsLoading(true);
        })
    }, []);
    return (
        <div>
            <h1>文章列表</h1>
            {isLoading ? <div>加载中</div> :
                posts.map(p => <div key={p.id}>
                {p.id}
            </div>)}
        </div>
    )
};

export default PostsIndex;

当网络不好的时候,loading 的时间很长,页面肯能会出现长时间白屏

由于初次请求的 HTML 中并没有文章内容,需要通过 AJAX 异步加载数据,而这个加载数据渲染的过程都是在客户端完成的,所以称为客户端渲染


静态页面生成 SSG

在文章列表页面里,其实每个用户查到的内容都是一样的

那为什么还需要在每个人的浏览器上渲染一遍呢?

为什么不在后端渲染好,然后发给每个人

这样就可以

N 次渲染变成了 1 次渲染

N 次客户端渲染变成了 1 次静态页面生成

这个过程成为 动态内容静态化

优缺点

优点:这种方式可以解决白屏问题、SEO 问题

缺点:所有用户看到的都是同一个页面,无法生成用户相关内容

如何实现

首先我们来想一个问题

该如何获取 posts 呢? 因为加载数据的操作在后端,想通过 AJAX 获取 posts 显然不合适

答案是: 通过 getStaticProps 获取 posts

getStaticProps 是 Next.js 提供的一个方法,会在后端执行,返回一个 props,NextPage 在渲染的时候可以使用这个 props

代码

import {GetStaticProps, NextPage} from 'next';
import {getPosts} from '../../lib/posts';
import Link from 'next/link';
import * as React from 'react';

type Post = {
  id: string,
  title: string
}

type Props = {
  posts: Post[];
}
// props 中有下面导出的数据 posts
const PostsIndex: NextPage<Props> = (props) => {
  const {posts} = props;
	// 前后端控制台都能打印 -> 同构
  console.log(posts);
  return (
    <div>
      <h1>文章列表</h1>
      {posts.map(p => <div key={p.id}>
        <Link href={`/posts/${p.id}`}>
          <a>
            {p.id}
          </a>
        </Link>
      </div>)}
    </div>
  );
};

export default PostsIndex;
// 实现SSG
export const getStaticProps: GetStaticProps = async () => {
  const posts = await getPosts();
  return {
    props: {
      posts: JSON.parse(JSON.stringify(posts))
    }
  };
};

前端是怎么不通过 AJAX 获取到数据的

posts 数据我们只在服务器获取了,但又是怎样传递给前端的呢?

发现玄机

我们可以看到玄机就藏在 id 为 _NEXT_DATA__ 的 script 标签中,里面储存了传给前端的 props 数据

这就是同构 SSR 的好处,后端可以将数据直接传给前端,而不需要 AJAX 异步获取

静态化的时机

环境

  1.  开发环境 ,每次请求都会运行一次 getStaticProps 这是为了方便你修改代码重新运行
  2.  生成环境,getStaticProps 只在 build 是运行一次,这样可以提供一份 HTML 给所有的用户下载

如何体验生成环境

yarn build
yarn start

打包后我们可以会看到这样

解读

我看看到的页面前的三种图标,分别是 λ ○ ●

λ (Serve) SSR 不能自动创建 HTML (下面会介绍)

○ (Static) 自动创建 HTML (发现你没用到 props)

● (SSG) 自动创建 HTML + JSON (等你用到 props)

三种文件类型

build 完成后,我们查看.next 文件里面,发现 posts.html、posts.js、posts.json

  • posts.html 含有静态内容,用于用户直接访问
  • post.js 也含有静态内容,用于快速导航(与 HTML 对应)
  • posts.json 含有数据,跟 posts.js 结合得到页面

为什么不直接把数据放入 posts.js 呢?

显然是为了 posts.js 接受不同的数据,当我们展示每篇博客的时候,他们的样式相同,内容不同,就会用到这个功能

动态内容静态化

  • 如果动态内容与用户无关,那么可以提前静态化
  • 通过 getStaticProps 可以获取数据
  • 静态内容+数据(本地获取) 就得到了完整的页面
  • 代替了之前的 静态内容+动态内容(AJAX 获取)

服务端渲染(SSR)

如果页面和用户相关呢?

这种情况较难提前静态化,需要在 用户请求时,获取用户信息,然后 通过用户信息去数据库拿数据,如果非要做,就要给每个用户创建一个页面,有时候这些数据更新极快,无法提前静态化, 比如微博首页的信息流

那怎么办?

要么客户端渲染, 会出现白屏

要么服务端渲染 SSR,没有白屏

运行时机

无论时开发环境还是生成环境,都是在请求之后运行 getServerSideProps

代码

和 SSG 代码基本一致,不过使用了 getSeverSideProps

这段代码实现的时,服务器响应请求后获取浏览器信息,返回给前端展示

import {GetServerSideProps, NextPage} from 'next';
import * as React from 'react';
import {IncomingHttpHeaders} from 'http';

type Props = {
  browser: string
}
const index: NextPage<Props> = (props) => {
  return (
    <div>
      <h1>你的浏览器是 {props.browser}</h1>
    </div>
  );
};
export default index;

export const getServerSideProps: GetServerSideProps = async (context) => {
  const headers:IncomingHttpHeaders = context.req.headers;
  const browser = headers['user-agent'];
  return {
    props: {
      browser
    }
  };
};

SSR 原理

推荐 在后端 renderToString() 在前端 hydrate()

后端将页面渲染,返回 HTML String 格式,传递到前端,前端进行 hydrate() ,会保留 HTML 并附上时间监听,也就是说后端渲染 HTML,前端添加监听。

前端也会渲染一次,用以确保前后端渲染结果一致


本期内容就到这里啦~以上内容均可在 方包博客http://fang1688.cn 网站直接搜索名称访问哦。欢迎感兴趣的小伙伴试试,如果本文对您有帮助,也请帮忙点个 赞 + 在看 啦!❤️

欢迎大家加入方包的优派编程学习圈子,和多名小伙伴们一起交流学习,向方包 1 对 1 提问、跟着方包做项目、领取大量编程资源等。Q群891029429欢迎想一起学习进步的小伙伴~

另外方包最近开发了一款工具类的小程序「方包工具箱」,功能包括:抖音、小红书、快手去水印,天气预报,小说在线免费阅读(内含上万部热门小说),历史今天,生成图片二维码,图片识别文字,ai伪原创文章,数字摇号抽奖,文字转语音MP3功能...

送福利!关注下方的公众号:优派编程回复资料,即可获得软件app下载资源和python、java等编程学习资料!

   
点击卡片关注「优派编程」
定期分享 it编程干货

 ⬇️ 点击链接阅读原文直达 方包博客

分享到:
赞(0)

评论抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

免责声明:本站为非盈利性个人博客,博客所发布的一切源码、软件的文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。

本站信息来自网络,版权争议与本站无关,您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。访问和下载本站内容,说明您已同意上述条款。本站不贩卖软件,所有内容不作为商业行为。

如果有侵犯版权请发送邮箱至619018020@qq.com,我们会在24小时之内处理。

Copyright © 2019-2021知识学堂