Next.js学习笔记 | 青训营

138 阅读7分钟

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 forSSR 实战: 官网开发指南》(${
        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中也有一些没有弄明白的地方。还需要花时间去琢磨。

引用参考:

「Next.js 实战项目」第五届字节跳动青训营 - 前端专场 (juejin.cn)