服务端渲染nextjs项目接入经验总结分析
背景介绍
服务端渲染 nextjs@13 项目接入经验总结,本文重点介绍基本知识点/常用的知识点/关键知识点
为提高首屏渲染速度减少白屏时间提高用户体验及丰富技术面,开始调研和接入nextjs框架
nextjs是一套成熟的同构框架(一套代码能运行在服务端也能运行在浏览器)对比传统的客户端渲染的优势是首屏是带数据的。其它后续操作是一样的。理论上能比客户端渲染看到数据能快个100-200ms具体看实际统计,
服务端渲染大概流程图(图片来源于网络)

客户端渲染大概流程图

对比流程图服务端渲染更加简洁。
使用
环境
Node.js >= 18.17 nextjs13
安装
npx create-next-app@13
选择 src/ 目录 和 使用 App Router
大致目录结构
...
package.json
public
node_modules
src
|- app
|- page.tsx
|- layout.tsx
|- blog
|- page.tsx
|- layout.tsx
|- docs
|- page.tsx
|- layout.tsx
| -services
| -utils
...路由
大致路由为
注意这是约定路由 需要用page.tsx layout.tsx文件命名


内置API
head标签 import Head from 'next/head'
图片标签 import Image from 'next/image'
跳转标签 import Link from 'next/link'
script
import Script from 'next/script'路由相关
import { useRouter, useSearchParams, useParams, redirect } from 'next/navigation'请求头 import { headers } from 'next/headers'
服务器组件和客户端组件
服务器组件需要运行在服务器
主要特点有请求数据,服务端环境等
客户端组件运行在浏览器 标识 文件第一行增加 'use client'主要特点有事件,浏览器环境,react hooks
比较
| 操作 | 服务器组件 | 客户端组件 |
|---|---|---|
| 请求数据 | ✅ | ❌ |
| 访问后端资源(直接) | ✅ | ❌ |
| 在服务器上保留敏感信息(访问令牌、API密钥等) | ✅ | ❌ |
| 保持对服务器的大量依赖性/减少客户端JavaScript | ✅ | ❌ |
| 添加交互性和事件侦听器(onClick、onChange等) | ❌ | ✅ |
| 使用状态和生命周期(useState、useReducer、useEffect等) | ❌ | ✅ |
| 浏览器API | ❌ | ✅ |
| 自定义hooks | ❌ | ✅ |
| 使用React Class组件 | ❌ | ✅ |
开始填充业务代码
修改html页面
文件位置在/src/app/layout.tsx,可以进行标题修改等一系操作
import Head from "next/head";
export default async function RootLayout(props: any) {
return (
<html lang="en">
<Head>
<title>页面标题</title>
</Head>
<body>{props.children}</body>
</html>
);
}获取数据
async function getData() {
const res = await fetch('https://xxxxx.com/', { cache: 'no-store' })
if (!res.ok) {
throw new Error('Failed to fetch data')
}
return res.json()
}
export default async function Page() {
const data = await getData()
return <main>{JSON.stringify(data, null, 2)}</main>
}把浏览器的信息转发到服务端
这个例子是cookie有需求可以用放其它的
import { headers } from 'next/headers'
const getData = async () => {
const headersList = headers();
const cookie = headersList.get('Cookie');
const res = await fetch('https://xxx.com', {
cache: 'no-store',
headers: { cookie }
});
return res.json()
};处理全局通讯和数据
在/src/app 目录下增加 context.tsx/src/app/context.tsx
'use client';
import { createContext, useMemo } from 'react';
import { useImmer } from 'use-immer';
export const PropsContext = createContext({});
export function Context({ children, ...other }: any) {
const [GlobalState, setGlobalState] = useImmer<any>({
...other
});
const providerValue = useMemo(
() => ({ GlobalState, setGlobalState }),
[GlobalState]
);
return (
<PropsContext.Provider value={providerValue}>
{children}
</PropsContext.Provider>
);
}/src/app/layout.tsx
import React from 'react';
import { headers } from 'next/headers'
import { Context } from './context';
const getData = async () => {
const headersList = headers();
const cookie = headersList.get('Cookie');
const res = await fetch('https://xxx.com', {headers: {
cookie
}});
return res.json()
};
export default async function RootLayout(props: any) {
const useInfo = await getData();
return (
<html lang="en">
<body>
<div>header</div>
<Context useInfo={useInfo}>{props.children}</Context>
<div>footer</div>
</body>
</html>
);
}使用/src/app/blog/page.tsx
'use client';
import { PropsContext } from '@/app/context';
import { useContext } from 'react';
export default function A2() {
const { GlobalState, setGlobalState } = useContext<any>(PropsContext);
return (
<main>
{JSON.stringify(GlobalState, null, 2)}
<div
onClick={() => {
setGlobalState((s: any) => {
s.useInfo.name = '修改之后的名称';
});
}}
>
修改名称
</div>
</main>
);
}跳转
如果没有用户信息需要跳转到登录页
import { redirect } from 'next/navigation'
async function fetchTeam(id) {
const res = await fetch('https://...')
// 具体逻辑根据实际的来
if (!res.ok) return undefined
return res.json()
}
export default async function Profile({ params }) {
const team = await fetchTeam(params.id)
if (!team) {
redirect('/login')
}
// ...
}部署
如果不在根域名下需要在 next.config.js添加
路由名称根据实际来
{
basePath: '/router'
}然后在流水线nginx配置路由 /router* 转发到这个应用
如果 basePath 配置的 /router/' 对应nginx配置 /router/*
编写 Dockerfile
由于 FROM nodejs@xx 过不了镜像扫描 镜像里面又没有Node.js >= 18.17的只能使用提供最基础的镜像了
Dockerfile
FROM hub.xxx.com/basics/alpine:3.18.2 RUN apk add nodejs=18.18.2-r0 npm=9.6.6-r0 WORKDIR /app ADD . . RUN npm i RUN npm run build EXPOSE 3000 CMD ["sh", "-c", "NODE_ENV=$NODE_ENV npm run start"]
参考文档
https://vercel.com/guides/react-context-state-management-nextjs
以上就是服务端渲染nextjs项目接入经验总结分析的详细内容,更多关于服务端渲染nextjs项目接入的资料请关注脚本之家其它相关文章!
相关文章
JavaScript之通过年月获取月份的天数、日期格式化、时间、补零、Date、toLocaleString、Intl、
这篇文章主要介绍了JavaScript之通过年月获取月份的天数、日期格式化、时间、补零、Date、toLocaleString、Intl、DateTimeFormat、format的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧2024-03-03
详解ES6 export default 和 import语句中的解构赋值
这篇文章主要介绍了详解ES6 export default 和 import语句中的解构赋值,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧2019-05-05


最新评论