服务端渲染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项目接入的资料请关注脚本之家其它相关文章!
相关文章
从jQuery.camelCase()学习string.replace() 函数学习
camelCase函数的功能就是将形如background-color转化为驼峰表示法:backgroundColor。2011-09-09JavaScript中for与forEach分别如何跳出循环
forEach的优势一个是它的回调函数形成了一个作用域,它的curItem和i不会像for循环一样污染全局变量,这篇文章主要给大家介绍了关于JavaScript中for与forEach分别如何跳出循环的相关资料,需要的朋友可以参考下2024-01-01教你如何自定义百度分享插件以及bshare分享插件的分享按钮
在项目中我们常用到百度分享插件或者bshare分享插件,虽然官方都有自定义按钮的功能,但是毕竟还是只有少数几种,我们如何来制作有自己特色的分享按钮呢?2014-06-06
最新评论