Next.js学习笔记 | 青训营
这是我参与「第五届青训营 」伴学笔记创作活动的第 8 天
前置概念
前端B端和C端
B:类似教学管理平台,内部平台,内部用户,不公开,给一定范围的人使用。
C:如掘金,面向整个互联网,面向全体用户。
next.js用于开发C端而不是B端的框架。
CSR,SSR,SSG
CSR
客户端渲染(Client-Side Rendering)。常见的B端Web应用开发模式,前后端分离。
一般是通过前端开发模板代码,通过后端提供的接口连通数据。后端只负责数据处理,不与前端代码相关。
渲染服务在客户端进行,服务器直接返回不加工的HTML
是单页面应用,所需要的资源(HTML,CSS,JS等)在一次请求中加载完成,首屏时间更长(打开页面显示元素所需的时间)。
SSR
SSR(Server-Side Rendering)。
旧的SSR: 代码耦合度高,模板语言混杂编程语言使得维护起来很痛苦。在这之中,前端只负责UI和交互,其他怨言负责渲染逻辑。
同构SSR:
BFF:Backend For Frontend,服务于前端应用的后端
通常加在前端接口与后端之间。BFF不会直接操作数据库,而是对下游的请求数据进行拼接汇总,然后交给前端进行数据展示/交互。
同构SSR: 前后端一体化,一套React代码在服务器上运行一遍,达到浏览器又运行一遍,前端后端均参与渲染,首次渲染的HTML一样。
前端也要写接口,接口文件与页面不在一个目录下
SSG
静态站点生成(Static Site Generation),在构建过程中上传结果到CDN/磁盘中,每次访问直接把HTML返回给客户端,相当于静态资源。
这种方式带给服务器端的压力较小,在构建的时候上传到CDN中,就不用同SSR那样每次请求都处理一次,而是直接从CDN中拉取。
缺点是:只能用于偏静态的服务,对与用户相关的动态内容束手无策。所以可以称之为“静态”。
什么是Next.JS
React中含有SSR的API,但是使用中有很多工作式重复的,并且对于新手不算友好,所以推出了Next.js框架。
能够开发SSR或者SSG项目。
demo中的同构
同构保证能够触发页面中的事件。 如果没有同构,服务器端不能返回对应的JS。
个人理解:SSR要返回HTML,由于没设置同构,服务器端中没有拿到客户端的js。那么服务器返回的HTML中没有JS,即使客户端有这个事件,也相当于是没有定义。
脱水和注水(服务器端)
课堂上的比喻:鱼干
一条鱼晒干就是脱水,晒没晒都能吃。晒干后给他用水泡一下也能吃。
在项目中,默认信息的显示与服务器端对不上的时候,就会用到脱水和注水。当信息对不上的时候,采用服务器端的数据信息,这是注水。隐藏默认信息,这是脱水。
同构和脱水注水使用next.js都可以不用管。next.js还能帮助做优化。
next.js客户端开发
使用
npx create-next-app@latest --typescript
初始化新项目
特别:数据注入
useEffect 请求的数据能够在调试面板的network中找到接口,而使用next.js提供的方式是直接在页面中完成的。在network找不到接口。
数据注入的方式(可以用代码debugger;测试)
- getInitialProps,注水(旧的API)
这段代码运行在服务器端上面,返回一个data
在页面跳转的时候会走客户端的路由,直接访问会走在服务器端。
- getServerSideProps
不同在于,这个方法只会在服务器端走
需要用props包裹数据
- getStaticProps
SSG 还要加getStaticPaths
能够将所有可能的(访问)情况都列举出来
一般用于偏固定,数据不多的情况
CSS modules
给文件的类名加上一个哈希值的后缀,防止出现样式互串的形式。
使用:[name.module.scss]
Layout
在layout中定义默认样式,避免重复写
路由
基于文件系统的路由,在page目录下会自动生成路由
BFF层
pages下的api目录
作为服务器构建包,不影响客户端构建Bundle体积。作为API层访问,不是page。
路由跳转
next/link跳转
import link from "next/link"
<link href={ item.link } key = { index } >
<div className= { StyleSheet.card }>
<h2>{ item.label } & RangeError; </h2>
<p> { item.info } </p>
</div>
</link>
useRouter跳转
import { useRouter } from 'next/router'
function ActiveLink({ children, href }) {
const router = useRouter()
const style = {
marginRight: 10,
color: router.asPath === href ? 'red' : 'black'
},
const handleClick = (e) => {
e.preventDefault()
router.push(href)
}
return (
<a href= { href } onClick = { fhandleClick } style = { style } >
{ children }
</a>
)
}
还可以使用默认的windows.locale等方式。不过原生的方法不会进行diff对比渲染,性能上next提供的路由跳转更好。
header修改
可用于修改TDK(title,descrption,keywords) header部分对于SEO十分重要,每个页面都需要定制,否则会影响SEO效率。
<Head>
<title>{
`A Demo for《SSR 实战: 官网开发指南》(${
isMobile ? "移动端" : "PC端"
})`}</title>
<meta
name = "description"
content = {`A Demo for 《SSR 实战: 官网开发指南》(${
isMobile ? "移动端" : "pc端"
})`}
/>
< meta name="viewport" content="user - scalable=no" />
<meta name="viewport" content = "initial-scale=1,maximum-scale=1" />
<link rel="icon" href = "/favicon.ico" />
</Head>
多媒体适配
- CSS rem: 灵活换算
// 极小分辨率移动端设备
@mixin media-mini-mobile {
@media screen and (max-width: 25.875rem) {
@content;
}
}
// 介于极小分辨率和正常分辨率之间的移动端设备
@mixin media-between-mini-and-normal-mobile {
@media screen and (min-width: 25.876rem) and (max-width: 47.9375rem) {
@content;
}
}
// 移动端设备
@mixin media-mobile {
@media screen and (max-width: 47.9375rem) {
@content;
}
}
// ipad
@mixin media-ipad {
@media screen and (min-width: 47.9375rem) and (max-width: 75rem) {
@content;
}
}
- JS
DEMO中的参考
export const UserAgentContext = createContext<IUserAgentContextProps>({} as IUserAgentContextProps);
export const UserAgentProvider = ({ children }: IProps): JSX.Element => {
const [userAgent, setUserAgent] = useState<Environment>(Environment.none); // 服务器渲染初始化渲染未必是预期效果,none缓冲切换视觉)
// 监听本地缓存来同步不同页面间的主题(当前页面无法监听到,直接在顶部栏进行了类的切换)
useEffect(() => {
const checkUserAgent = (): void => {
const width = document.body.offsetWidth;
// 用宽度去判断,是为了适配不改机型,仅拉扯屏幕宽度的情况
if (width < 768) {
// 手机端
setUserAgent(Environment.mobile);
} else if (width >= 768 && width < 1200) {
// ipad端
setUserAgent(Environment.ipad);
} else if (width >= 1200) {
// pc端
setUserAgent(Environment.pc);
} else {
setUserAgent(Environment.none); // 增加none类型来缓冲默认类型样式切换时的视觉突变
}
};
checkUserAgent();
window.addEventListener('resize', checkUserAgent); // 监听屏幕宽度变化,及时适配当前页面样式
return (): void => {
window.removeEventListener('resize', checkUserAgent);
};
}, [typeof document !== 'undefined' && document.body.offsetWidth]);
return <UserAgentContext.Provider value={{ userAgent }}>{children}</UserAgentContext.Provider>;
};
图片优化 webp
能够将体积能够缩小到大约1/3.慢网速中加载有优势,快网速中,解析时间大于下载时间,体现的可能会比PNG还要慢。
此类型图片格式并不是所有设备兼容
通常要写一个方法判断浏览器是否支持Webp格式。如果不支持,使用其他格式如png显示。
next.js服务器端开发
BFF层开发
不限制请求类型,用POST和GET是一样的。
使用JS的debugger控制台进行debug。
CMS 后台管理平台
Strapi 能够快读搭建数据管理平台
初始化:
npx create-strapi-app my-project --quickstart
一个接口的生成有以下几个过程 :
1.content-type builder 编辑结构体
2. content manager 配置数据源,并且发布
3.settings roles 里选择对应角色并勾选要发布的接口类型
4.(子结构体)如果涉及嵌套,在接口后加上 populate=deep 参数 (npm install strapi-plugin-populate-deep --save), 没安装可用参数populate=* ,但只能嵌套一层
markdown转化成HTML
npm install showdown --save
需要注意的是,配置完成后没有样式,需要自己写CSS配置样式
结尾
本文主要记录一些青训营Next.js部分的学习内容。作为后续回顾的时候参考使用。
这节课收获很大,通过学习这节课,使我对next.js和SSR有了新的认识,如果说前天在去山的路上,昨天在山底,那么今天应该在半山腰了。但是,demo中也有一些没有弄明白的地方。还需要花时间去琢磨。
引用参考: