亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

服務(wù)端渲染nextjs項目接入經(jīng)驗總結(jié)分析

 更新時間:2023年11月09日 10:00:50   作者:路邊縣  
這篇文章主要為大家介紹了服務(wù)端渲染nextjs項目接入經(jīng)驗總結(jié)分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

背景介紹

服務(wù)端渲染 nextjs@13 項目接入經(jīng)驗總結(jié),本文重點(diǎn)介紹基本知識點(diǎn)/常用的知識點(diǎn)/關(guān)鍵知識點(diǎn)

為提高首屏渲染速度減少白屏?xí)r間提高用戶體驗及豐富技術(shù)面,開始調(diào)研和接入nextjs框架

nextjs是一套成熟的同構(gòu)框架(一套代碼能運(yùn)行在服務(wù)端也能運(yùn)行在瀏覽器)對比傳統(tǒng)的客戶端渲染的優(yōu)勢是首屏是帶數(shù)據(jù)的。其它后續(xù)操作是一樣的。理論上能比客戶端渲染看到數(shù)據(jù)能快個100-200ms具體看實際統(tǒng)計,

服務(wù)端渲染大概流程圖(圖片來源于網(wǎng)絡(luò))

客戶端渲染大概流程圖

對比流程圖服務(wù)端渲染更加簡潔。

使用

環(huán)境

Node.js >= 18.17 nextjs13

安裝

npx create-next-app@13

選擇 src/ 目錄 和 使用 App Router

大致目錄結(jié)構(gòu)

...
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文件命名

內(nèi)置API

head標(biāo)簽  import Head from 'next/head'

圖片標(biāo)簽 import Image from 'next/image'

跳轉(zhuǎn)標(biāo)簽 import Link from 'next/link'

script
import Script from 'next/script'

路由相關(guān)
import { useRouter, useSearchParams, useParams, redirect } from 'next/navigation'

請求頭 import { headers } from 'next/headers'

服務(wù)器組件和客戶端組件

服務(wù)器組件需要運(yùn)行在服務(wù)器
主要特點(diǎn)有請求數(shù)據(jù),服務(wù)端環(huán)境等

客戶端組件運(yùn)行在瀏覽器 標(biāo)識 文件第一行增加 'use client'主要特點(diǎn)有事件,瀏覽器環(huán)境,react hooks

比較

操作服務(wù)器組件客戶端組件
請求數(shù)據(jù)??
訪問后端資源(直接)??
在服務(wù)器上保留敏感信息(訪問令牌、API密鑰等)??
保持對服務(wù)器的大量依賴性/減少客戶端JavaScript??
添加交互性和事件偵聽器(onClick、onChange等)??
使用狀態(tài)和生命周期(useState、useReducer、useEffect等)??
瀏覽器API??
自定義hooks??
使用React Class組件??

開始填充業(yè)務(wù)代碼

修改html頁面

文件位置在/src/app/layout.tsx,可以進(jìn)行標(biāo)題修改等一系操作

import Head from "next/head";
export default async function RootLayout(props: any) {
  return (
 <html lang="en">
   <Head>
     <title>頁面標(biāo)題</title>
   </Head>
   <body>{props.children}</body>
 </html>
  );
}

獲取數(shù)據(jù)

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>
}

把瀏覽器的信息轉(zhuǎn)發(fā)到服務(wù)端
這個例子是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()
};

處理全局通訊和數(shù)據(jù)

在/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>
  );
}

跳轉(zhuǎn)

如果沒有用戶信息需要跳轉(zhuǎn)到登錄頁

import { redirect } from 'next/navigation'
async function fetchTeam(id) {
  const res = await fetch('https://...')
  // 具體邏輯根據(jù)實際的來
  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添加

路由名稱根據(jù)實際來

{
  basePath: '/router'
}

然后在流水線nginx配置路由 /router* 轉(zhuǎn)發(fā)到這個應(yīng)用

如果 basePath 配置的 /router/' 對應(yīng)nginx配置 /router/*

編寫 Dockerfile

由于 FROM nodejs@xx 過不了鏡像掃描 鏡像里面又沒有Node.js >= 18.17的只能使用提供最基礎(chǔ)的鏡像了

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://nextjs.org/docs

https://vercel.com/guides/react-context-state-management-nextjs

以上就是服務(wù)端渲染nextjs項目接入經(jīng)驗總結(jié)分析的詳細(xì)內(nèi)容,更多關(guān)于服務(wù)端渲染nextjs項目接入的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論