next是一款用JS开发的全栈框架,它是基于express框架基础上开发而成,可以用react写客户端,node.js写服务端。一份代码可在前后端同时运行,这在next中称之为同构!
创建项目:npm init next-app 项目名,项目创建好后next会帮你搭好基础通用的模板,大多常用的api以及写法都能在模板中找到。
自定义head:使用<Head>组件可自定义<title><meta>标签和内容组件导入。
// 文件路径 page/_app.js
import Head from "next/head";
import '../styles/globals.scss'
export default function App({ Component, pageProps }) {
return <>
<Head>
<title>我的博客 A-Tione</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover"/>
</Head>
<Component {...pageProps} />
</>
}
SSR与SSG都属于预渲染Pre-rendering,Next.js的预渲染可以与前端React无缝对接。
Next.js有两种预渲染形式:静态生成(Static Generation)和服务端渲染(Server-side Rendering)。 不同之处在于他们为页面生成HTML代码的时间
客户端渲染,顾名思义就是只在浏览器上执行的渲染,指用浏览器JS创建的HTML代码。
通过Vue 、 React、angularJS 构建的单页面应用SPA 都是采用这种方式渲染
import {NextPage} from 'next';
import {usePosts} from '../../hooks/usePosts';
const PostsIndex: NextPage = () => {
const {posts, isLoading, isEmpty} = usePosts();
return (
<div>
<h1>文章列表</h1>
{isLoading ? <div>加载中</div> :
isEmpty ? <div>没有文章</div> :
posts.map(p => <div key={p.id}>
{p.id}
</div>)
}
</div>
);
};
export default PostsIndex;
后端:
import {useEffect, useState} from 'react';
import axios from 'axios';
export const usePosts = () => {
const [posts, setPosts] = useState<Post[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [isEmpty, setIsEmpty] = useState(false);
useEffect(() => {
setIsLoading(true);
axios.get('api/v1/posts').then(response => {
setPosts(response.data);
setIsLoading(false);
if (response.data.length === 0) {
setIsEmpty(true);
}
}, () => {
setIsLoading(false);
});
}, []);
return {posts, setPosts, isLoading, setIsLoading, isEmpty, setIsEmpty};
};
文章列表完全前端渲染的,可称之为客户端渲染。
一般来说,静态内容在代码里写死的,动态内容是来自数据库的。
在next中,图上的静态内容会在服务器渲染一次,客户端再渲染一次,为什么?
在React SSR官方文档中提到:推荐后端使用renderToString(),在前端hydrate()。前端hydrate()混合指的是会保留HTML并附上事件监听,也就是说后端渲染HTML,前端添加监听,前端也会渲染一次来保证前后端渲染结果一致。next框架已经帮我们做好了这一步。
在文章列表页面里,其实每个用户查到的内容都是一样的
为什么不在后端渲染好,然后发给每个人
这样就可以
这个过程成为 动态内容静态化
如果每个人都请求一个相同的资源,比如都请求相同的文章列表,那还需要在每个人的浏览器上渲染一次吗?直觉告诉我们是不是大可不必,可以直接在后端渲染好,然后每个人直接读取后端传来的内容。
n次渲染变成了一次渲染,n次客户端渲染变成了1次静态页面生成。这个过程叫做动态内容静态化。
那么后端渲染还需要通过ajax来获取渲染内容么?也可以,axios支持服务端使用,但是这样有点傻,资源就在服务端为什么还需要绕远路请求ajax来获取一次资源呢?
我们可以在服务端这样写:
通过getStaticProps获取内容。声明位置:每个page不是默认导出一个函数么,把getStaticProps声明在这个函数旁边即可,默认export导出。
import {NextPage} from ' next';
import Link from ' next/link';
import {getPosts} from '../.. /lib/posts';
type Post = {
id: string,
title: string}
type Posts = {
posts: Post[];
}
const Postslndex: NextPage<Posts> = (props => {
const {posts} = props;
return (
<div>
<h1>文章列表</h1>
{posts.map(p=>{(
<div key={p.id}>
<Link href={ `/post/${p.id}`}>><a>{p.id}</a></Link>
</div>
)})}
</div>
)
})
export default Postslndex;
export const getStaticProps = async () => {
const posts = await getPosts();
return {
props: {
posts: '内容XXX'
}
}
}
因为加载数据的操作在后端,想通过 AJAX 获取 posts 显然不合适
答案是: 通过 getStaticProps 获取 posts
getStaticProps 是 Next.js 提供的一个方法,会在后端执行,返回一个 props,NextPage 在渲染的时候可以使用这个 props
getStaticProps:
export default function PostsIndex = (props)=> { ... }
我们可以看到玄机就藏在 id 为 _NEXT_DATA__ 的 script 标签中,里面储存了传给前端的 props 数据
通过同构,前端也可以不用ajax就能拿到数据了,这就是同构的好处:后端数据可以直接传给前端,然后前端JSON.parse一下就能得到了posts(next框架已经帮我们做了parse)。
这就是同构 SSR 的好处,后端可以将数据直接传给前端,而不需要 AJAX 异步获取
显然是为了 posts.js 接受不同的数据,当我们展示每篇博客的时候,他们的样式相同,内容不同,就会用到这个功能
build 完成后,我们查看.next 文件里面,发现 posts.html、posts.js、posts.json
思路是一样的,他们也能做,但是他们不支持jsx,不好与React无缝对接,而且这些语言的对象不能直接提供给JS用,需要类型转换。
所有用户看到的都是同一个页面,无法生成用户相关内容
这种情况较难提前静态化,需要在 用户请求时,获取用户信息,然后 通过用户信息去数据库拿数据,如果非要做,就要给每个用户创建一个页面,有时候这些数据更新极快,无法提前静态化, 比如微博首页的信息流
如果是与用户相关的动态内容,较难提前静态化,需要在用户请求时,获取用户信息,然后通过用户信息去数据库拿数据。有时候这些数据更新极快,无法提前静态化,比如微博首页。
这些更新极快的内容我们可以
但这次的服务端渲染不能用getStaticProps,因为getStaticProps是在build时执行的,可用getServerSideProps(context: NextPageContent)。
getServerSideProps:
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))
}
};
};
推荐 在后端 renderToString() 在前端 hydrate()
SSR无法获取客户端信息,比如浏览器大小。必须要用户通过客户端实际登录发送具体请求后才能知道客户端的信息,仅通过用户信息是无法得知具体的客户端信息。
参考文章:
node.js Next框架的三种渲染方式:客户端渲染、SSG、SSR https://blog.csdn.net/weixin_41819731/article/details/109899642
Next.js 的三种渲染方式(BSR、SSG、SSR) https://zhuanlan.zhihu.com/p/341229054
转载本站文章《next.js静态页面渲染技术(静态生成和服务端渲染):BSR/SSG/SSG》, 请注明出处:https://www.zhoulujun.cn/html/webfront/server/nextjs/8793.html
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。