React19 她來了,她來了,他帶著禮物走來了
前言
xdm,5.1玩的還可以嗎?既然已經玩夠了,那么我們又得切換到上班模式。其實這篇文章是5.1之前開始寫的,為了讓大家能夠有一個輕松的假期,索性就沒在節內發送。今天我們來聊聊前端的內容。
React19她來了,她來了,她帶著??走來了。時隔2年多,React終于有了新版本了。你可知道,我們這兩年是如何過來的嗎?!
就在2024/04/25,我們可以通過npm install react@beta在本地安裝React19了。
圖片
在React19沒發布之前,從各種小道消息中知曉了React在新版本中新增了很多特性,并且優化了編譯流程。因為,本著沒有調查就沒有發言權的態度,我就遲遲沒有下筆。
既然,React19我們可以唾手可得了,那高低需要研究一波。
下面,我們就來看看她到底給我帶來了啥!
好了,天不早了,干點正事哇。
我們能所學到的知識點
- React v19 的新特性概覽
- React 編譯器
- 服務器組件(RSC)
- 動作(Action)
- Web Components
- 文檔元數據
- 資源加載
- 新的 React Hooks
1. React v19 的新特性概覽
- React 編譯器:React 實現了一個新的編譯器。目前,Instagram 已經在利用這項技術了。
- 服務器組件(RSC):經過多年的開發,React 引入了服務器組件,而不是需要借助Next.js
- 動作(Action):動作也將徹底改變我們與 DOM 元素的交互方式。
- 文檔元數據:這是另一個備受期待的改進,讓我們能夠用更少的代碼實現更多功能。
- 資源加載:這將使資源在后臺加載,從而提高應用程序的加載速度和用戶體驗。
- Web Components:React 代碼現在可以讓我們集成 Web Components。
- 增強的 hooks:引入了很多令人興奮的新 hooks,將徹底改變我們的編碼體驗。
下面我們就來一一探索其中的奧秘。
2. React 編譯器
其實React 編譯器就是之前早在React 2021年開發者大會上提出的React Forget,只不過最近才將其改為React 編譯器。
React 編譯器是一個「自動記憶編譯器」,可以自動執行應用程序中的所有記憶操作。
React 編譯器 的核心幾乎與 Babel 完全解耦,編譯器內核其實就是「舊的 AST 輸入,新的 AST 輸出」。在后臺,編譯器使用自定義代碼表示和轉換管道來執行語義分析。
React19之前的版本,當狀態發生變化時,React有時會重新渲染不相干的部分。從React的早期開始,我們針對此類情況的解決方案一直是「手動記憶化」。在之前的API中,這意味著應用useMemo、useCallback和memo API來手動調整React在狀態變化時重新渲染的部分。但手動記憶化只是一種「權宜之計」,它會使代碼變得復雜,容易出錯,并需要額外的工作來保持更新。React 團隊意識到手動優化很繁瑣,并且使用者對這種方式「怨聲載道」。
因此,React 團隊創建了React 編譯器。React 編譯器現在將管理這些重新渲染。React 將「自行決定何時以及如何改變狀態并更新 UI」。
有了這個功能,我們不再需要手動處理這個問題。這也意味著讓人詬病的 useMemo()、useCallback() 和 memo要被歷史的車輪無情的碾壓。
React19 !=React 編譯器
圖片
由于React 編譯器還未開源,所以我們無法得知其內部實現細節,不過我們可以從以往的動態中窺探一下。下面是一些與其相關的資料和視頻。
- React 編譯器_youtube地址[1]
- React Forget的基本介紹[2]
3. 服務器組件(RSC)
其實,在2023年,我們就注意到RSC,并且寫了幾篇文章。
圖片
對應的文章鏈接如下
- React Server Components手把手教學
- 用Rust搭建React Server Components 的Web服務器
服務器組件的想法已經流傳了多年,Next.js 是第一個在生產環境中實現它們的。從 Next.js 13 開始,「默認情況下所有組件都是服務器組件」。要使組件在客戶端運行,我們需要使用'use client'指令。
在 React 19 中,服務器組件將直接集成到 React 中,帶來了一系列優勢:
- 數據獲取: 服務器組件允許我們將數據獲取移至服務器端,更接近數據源。這可以通過減少獲取渲染所需數據的時間和客戶端需要發出的請求數量來提高性能。
- 安全性: 服務器組件允許我們將「敏感數據和邏輯」保留在服務器端,而無需暴露給客戶端的風險。
- 緩存: 由于在服務器端渲染,結果可以被緩存并在后續請求和跨用戶時重復使用。這可以通過減少每個請求所需的渲染和數據獲取量來提高性能并降低成本。
- 性能: 服務器組件為我們提供了額外的工具來從基線優化性能。例如,如果我們從一個完全由客戶端組件組成的應用程序開始,將非交互式UI部分移至服務器組件可以減少所需的客戶端JavaScript。這對于網絡較慢或設備性能較低的用戶來說是有益的,因為瀏覽器需要下載、解析和執行的客戶端JavaScript更少。
- 初始頁面加載和首次內容渲染(FCP): 在服務器端,我們可以生成HTML,允許用戶立即查看頁面,而無需等待客戶端下載、解析和執行渲染頁面所需的JavaScript。
- SEO:RSC通過為網絡爬蟲提供更可訪問的內容來增強搜索引擎優化。
- 流式傳輸: 服務器組件允許我們將渲染工作分割成塊,并在它們準備就緒時將其流式傳輸到客戶端。這允許用戶在不必等待整個頁面在服務器端渲染完成的情況下,更早地看到頁面的某些部分。
如何使用服務器組件
默認情況下,React 中的所有組件都是客戶端組件。只有使用 'use server' 時,組件才是服務器組件。
我們只需要將 'use server' 添加為組件的第一行即可。這將使組件成為服務器組件。它不會在客戶端運行,只會在服務器端運行。
'use server';
export default async function requestUsername(formData) {
const username = formData.get('username');
if (canRequest(username)) {
// ...
return 'successful';
}
return 'failed';
}
4. 動作(Action)
在 React19中,另一個令人興奮的新增功能將是Action。這將是我們處理表單的重大變革。
何為Action
使用異步轉換的函數被稱為Action(動作)。Action自動管理數據的提交:
- Pending狀態:Action提供了一個state
請求開始時,代表對應的狀態- pending狀態
請求結束時,狀態自動重置
- Optimistic更新:Action支持新的useOptimistic hook,因此我們可以在請求提交時向用戶顯示即時反饋。
- 錯誤處理:Action提供錯誤處理,因此我們可以在請求失敗時顯示Error Boundary,并自動恢復Optimistic更新為其原始值。
- 增強表單操作:<form>元素支持將函數傳遞給action和formAction props。
傳遞給action props的函數默認使用Action機制,并在提交后自動重置表單
Action將允許我們將action與<form/>標簽 集成。簡單來說,我們將能夠用action替換 onSubmit 事件。
在使用Action之前
在下面的代碼片段中,我們將利用 onSubmit事件,在表單提交時觸發搜索操作。
<form notallow={search}>
<input name="query" />
<button type="submit">查詢</button>
</form>
使用Action后
隨著服務器組件的引入, Action可以在服務器端執行。在我們的 JSX 中,我們可以刪除 <form/> 的 onSubmit 事件,并使用 action 屬性。action 屬性的值將是一個「提交數據的方法」,可以在客戶端或服務器端提交數據。
我們可以使用Action執行同步和異步操作,簡化數據提交管理和狀態更新。目標是使處理表單和數據更加容易。
"use server"
const submitData = async (userData) => {
const newUser = {
username: userData.get('username'),
email: userData.get('email')
}
console.log(newUser)
}
const Form = () => {
return <form action={submitData}>
<div>
<label>用戶名</label>
<input type="text" name='username'/>
</div>
<div>
<label>郵箱</label>
<input type="text" name="email" />
</div>
<button type='submit'>提交</button>
</form>
}
export default Form;
在上面的代碼中,submitData 是服務器組件中的Action。form 是一個客戶端組件,它使用 submitData 作為Action。submitData 將在服務器上執行。
5. Web Components
如果大家公司技術方案不是單一的。例如,公司有很多項目,并且項目中使用了不同的技術框架React/Vue等。然而,此時有一個功能需要多項目多框架使用,那么我們可以考慮一下,將此功能用Web Components實現。
Web Components
Web 組件允許我們使用原生 HTML、CSS 和 JavaScript 創建自定義組件,無縫地將它們整合到我們的 Web 應用程序中,就像使用HTML 標簽一樣。
三要素
- Custom elements(自定義元素):一組 JavaScript API,允許我們定義 custom elements 及其行為,然后可以在我們的用戶界面中按照需要使用它們。
通過 class A extends HTMLElement {} 定義組件,
通過 window.customElements.define('a-b', A) 掛載已定義組件。
- Shadow DOM(影子 DOM ):一組 JavaScript API,用于將封裝的“影子” DOM 樹附加到元素(「與主文檔 DOM 分開呈現」)并控制其關聯的功能。
通過這種方式,我們可以「保持元素的功能私有」,這樣它們就可以被腳本化和樣式化,而不用擔心與文檔的其他部分發生沖突。
使用 const shadow = this.attachShadow({mode : 'open'}) 在 WebComponents 中開啟。
HTML templates(HTML 模板)slot :template 可以簡化生成 dom 元素的操作,不再需要 createElement 每一個節點。
雖然 WebComponents 有三個要素,但卻不是缺一不可的,WebComponents
- 借助 shadow dom 來實現「樣式隔離」,
- 借助 templates 來「簡化標簽」的操作。
內部生命周期函數(4個)
- connectedCallback: 當 WebComponents 「第一次」被掛在到 dom 上是觸發的鉤子,并且只會觸發一次。
類似 React 中的 useEffect(() => {}, []),componentDidMount。
- disconnectedCallback: 當自定義元素與文檔 DOM 「斷開連接」時被調用。
- adoptedCallback: 當自定義元素被「移動」到新文檔時被調用。
- attributeChangedCallback: 當自定義元素的被監聽屬性變化時被調用。
如果不想用原生寫,那么我們可以選擇一些成熟的框架,例如Lit[3]
圖片
React19 兼容 Web Components
在React19之前,在 React 中集成 Web Components并不直接。通常,我們需要將 Web Components轉換為 React 組件,或者安裝額外的包并編寫額外的代碼來使 Web Components與 React 協同工作。
React 19 將幫助我們更輕松地將 Web Components整合到我們的 React 代碼中。如果我們遇到一個非常有用的 Web Components,我們可以無縫地將其整合到 React 項目中,而不需要將其轉換為 React 代碼。
這簡化了開發流程,并允許我們在 React 應用程序中利用現有 Web Components的廣泛生態系統。
6. 文檔元數據
TKD
在做SEO時,我們需要在<meta>中處理title/keywords/description的信息。
- title的權重最高,利用title提高頁面權重
- keywords相對權重較低,作為頁面的輔助關鍵詞搜索
- description的描述一般會直接顯示在搜索結果的介紹中
當然處理SEO不僅僅這點方式,還有在項目中新增Sitemap.xml還有使用rel=canonical的連接,想了解更多的方式,可以參考SEO教程[4]
處理SEO
經常借助編寫自定義代碼或使用像 react-helmet[5] 這樣的包來處理路由更改并相應地更新元數據。這個過程可能會重復,而且容易出錯,特別是在處理像 meta 標簽這樣對 SEO 敏感的元素時。
React19之前的SEO
import React, { useEffect } from 'react';
const HeadDocument = ({ title }) => {
useEffect(() => {
document.title = title;
const metaDescriptionTag = document.querySelector('meta[name="description"]');
if (metaDescriptionTag) {
metaDescriptionTag.setAttribute('content', '前端柒八九');
}
}, [title]);
return null;
};
export default HeadDocument;
在上面的代碼中,我們有一個名為 HeadDocument 的組件,基于props 更新title和 meta 標簽。我們在 useEffect 鉤子中更新這些內容。我們還使用 JavaScript 來更新標題和 meta 標簽。這個組件將在路由更改時更新。
React19的SEO
使用 React19后,我們可以直接在 React 組件中使用<title>和 <meta> 標簽:
Const HomePage = () => {
return (
<>
<title>React19</title>
<meta name="description" content="前端柒八九" />
// 頁面內容
</>
);
}
當然,我們可以基于props來更新title/meta中的對應信息。
7.資源加載
在 React 中,我們需要特別關心應用程序的加載體驗和性能,特別是圖片和其他資源文件。
通常,視圖會首先在瀏覽器中渲染,然后是樣式表、字體和圖片。這可能會導致FOIT或者FOUT。
我們在瀏覽器之性能指標-CLS中有過介紹,這里我們就拿來主義了。
FOIT/FOUT
FOIT和FOUT是與Web字體加載相關的術語。
FOIT代表"Flash of Invisible Text",意為「不可見文本的閃爍」。
當使用Web字體時,瀏覽器在下載字體文件時,會顯示一段時間的空白文本,直到字體文件完全加載完成。這段時間內,用戶可能會看到頁面上出現了空白文本,然后突然閃現出字體樣式。這種體驗被稱為FOIT。
FOUT代表"Flash of Unstyled Text",意為「未樣式化文本的閃爍」。
與FOIT類似,當使用Web字體時,瀏覽器可能會「先顯示系統默認字體」,然后在字體文件加載完成后,突然將文本樣式化為所需的Web字體。這種體驗被稱為FOUT。
FOIT和FOUT都是由于Web字體加載的延遲而導致的不佳用戶體驗。用戶可能會看到文本內容在加載過程中發生閃爍或樣式變化,給頁面的整體穩定性和一致性帶來了困擾。為了解決FOIT和FOUT問題,可以使用CSS屬性,如font-display,來控制字體加載和顯示的方式,以平滑地呈現文本內容,提高用戶體驗。
或者我們可以「添加自定義代碼來檢測這些資源何時準備好」,確保視圖只在所有內容加載完畢后顯示。
在 React 19 中,當用戶瀏覽當前頁面時,圖片和其他文件將「在后臺加載」。
這個改進應該有助于提高頁面加載速度并減少等待時間。
此外,React 還引入了用于資源加載的生命周期 Suspense,包括script、樣式表和字體。這個特性使 React 能夠確定內容何時準備好顯示,消除了任何FOUT的閃爍現象。
還有新的資源加載 API,比如 preload 和 preinit,可以提供更大的控制力,確定何時加載和初始化資源。
通過允許資源在后臺異步加載,React 19減少了等待時間,確保用戶可以在不間斷的情況下與內容進行交互。
8. 新的 React Hooks
自從React16.8引入Hook機制以來,React的開發模式就發生了翻天覆地的變化。她提供的各種內置Hook大大提高了我們開發組件的效率。并且,我們還可以通過封裝各種自定義Hook來處理共有邏輯。也就是說,Hook在React中有舉足輕重的地位。Hook已經成為了開發React的主流編程模式。
雖然,Hook為我們帶來了很多的便利,但是有些Hook的使用卻需要各種限制,稍不留神就會讓頁面陷入萬劫不復的地步。所以React19對一些我們平時用起來不咋得心應手的Hook做了一次升級。
在 React 19 中,我們使用 useMemo、forwardRef、useEffect 和 useContext 的方式將會改變。這主要是因為將引入一個新的 hook,即 use。
useMemo()
在 React19 之后,我們不再需要使用 useMemo() hook,因為 React編譯器 將會自動進行記憶化。
之前的寫法
import React, { useState, useMemo } from 'react';
function ExampleComponent() {
const [inputValue, setInputValue] = useState('');
// 記住輸入框是否為空的檢查結果
const isInputEmpty = useMemo(() => {
console.log('檢測輸入框是否為空');
return inputValue.trim() === '';
}, [inputValue]);
return (
<div>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<p>{isInputEmpty ? 'Input 為空' : 'Input有值'}</p>
</div>
);
}
export default ExampleComponent;
之后的寫法
在下面的例子中,我們可以看到在 React19 之后,我們不再需要自己來做記憶化,React19 將會在后臺自動完成。
import React, { useState } from 'react';
function ExampleComponent() {
const [inputValue, setInputValue] = useState('');
const isInputEmpty = () => {
console.log('檢測輸入框是否為空');
return inputValue.trim() === '';
});
return (
<div>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<p>{isInputEmpty ? 'Input 為空' : 'Input有值'}</p>
</div>
);
}
export default ExampleComponent;
forwardRef()
ref 現在將作為props傳遞而不是使用 forwardRef() hook。
這將簡化代碼。因此,在 React19 之后,我們不需要使用 forwardRef()。
之前的寫法
import React, { forwardRef } from 'react';
const ExampleButton = forwardRef((props, ref) => (
<button ref={ref}>
{props.children}
</button>
));
之后的寫法
ref 可以作為屬性傳遞。不再需要 forwardRef()。
import React from 'react';
const ExampleButton = ({ ref, children }) => (
<button ref={ref}>
{children}
</button>
);
新的 use() hook
React19 將引入一個新的 hook,名為 use()。這個 hook 將簡化我們如何使用 promises、async 代碼和 context。
語法
const value = use(resource);
示例1:接收async函數
下面的代碼是使用 use hook 進行 fetch 請求的示例:
import { use } from "react";
const fetchUsers = async () => {
const res = await fetch("遠程地址");
return res.json();
};
const UsersItems = () => {
const users = use(fetchUsers());
return (
<ul>
{users.map((user) => (
<div key={user.id} >
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
))}
</ul>
);
};
export default UsersItems;
讓我們理解一下代碼:
- fetchUsers進行遠程數據請求
- 我們使用 use hook 執行 fetchUsers,而不是使用 useEffect 或 useState hooks。
- use hook 的返回值是 users,其中包含 GET 請求的響應(users)。
- 在return中,我們使用 users進行對應信息的渲染處理。
示例2:接收context對象
我們以后可以直接將context對象傳人到use()中,從而達到將context引入組件的目的。而不需要useContext()了。
使用createContext定義全局變量
這里我們定義
import { createContext, useState, use } from 'react';
const ThemeContext = createContext();
const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
在組件中使用use()獲取context信息
const Card = () => {
// use Hook()
const { theme, toggleTheme } = use(ThemeContext);
return (
// 基于theme/toggleTheme 渲染頁面或者執行對應的操作
);
};
const Theme = () => {
return (
<ThemeProvider>
<Card />
</ThemeProvider>
);
};
export default Theme
上面代碼中有幾點需要簡單解釋一下:
- ThemeProvider 負責提供 context。
- Card 是我們將消費 context 的組件。為此,我們將使用新的 hook use 來消費 context。
衍生一下
其實吧,use的內部實現很簡單,就是基于傳人的對象類型進行返回數據即可。
圖片
針對,其內部是如何實現的,我們后期會有專門的文章來介紹,這里就不在過多解釋了。
useFormStatus() hook
在 React19 中,我們還有新的 hooks 來處理表單狀態和數據。這將使處理表單更加流暢和簡單。將這些 hooks 與 Action結合使用將使處理表單和數據更加容易。
React19 中的這個新 hook 將幫助我們更好地控制你創建的表單。它將提供關于上次表單提交的狀態信息。
基礎語法
這是它的語法:
const { pending, data, method, action } = useFormStatus();
或者簡化的版本:
const { status } = useFormStatus()
- pending:如果表單處于待處理狀態,則為 true,否則為 false。
- data:一個實現了 FormData 接口的對象,其中包含父 <form> 提交的數據。
- method:HTTP 方法 – GET,或 POST。
默認情況下將是 GET。
- action:一個函數引用。
案例展示
useFormStatus是從react-dom庫中導出的
import { useFormStatus } from "react-dom";
function Submit() {
const status = useFormStatus();
return <button disabled={status.pending}>
{status.pending ? '正在提交...' : '提交完成'}
</button>;
}
// ==== 父組件 ==引入Submit ====
const formAction = async () => {
// 模擬延遲 3 秒
await new Promise((resolve) => setTimeout(resolve, 3000));
}
const FormStatus = () => {
return (
<form action={formAction}>
<Submit />
</form>
);
};
export default FormStatus;
讓我們簡單解釋一下上面代碼:
- Submit通過useFormStatus可以獲取此時from表單的提交狀態,并基于一些狀態渲染一些輔助信息
- formAction是執行異步提交的處理
在上面的代碼中,當表單提交時,從 useFormStatus hook 我們將獲得一個 pending 狀態。
- 當 pending 為 true 時,UI 上會顯示 "正在提交..." 文本。
- 一旦 pending 為 false,"正在提交..." 文本將被更改為 "提交完成"。
當我們想要知道表單提交的狀態并相應地顯示數據時,它會很有用。
useFormState() hook
React19 中的另一個新 hook 是 useFormState。它允許我們根據表單提交的結果來更新狀態。
語法
這是它的語法:
const [state, formAction] =
useFormState(
fn,
initialState,
permalink?
);
- fn:表單提交或按鈕按下時要調用的函數。
- initialState:我們希望狀態初始值是什么。它可以是任何可序列化的值。在首次調用操作后,此參數將被忽略。
- permalink:這是可選的。一個 URL 或頁面鏈接,如果 fn 將在服務器上運行,則頁面將重定向到 permalink。
這個 hook 將返回:
- state:初始狀態將是我們傳遞給 initialState 的值。
- formAction:一個將傳遞給表單操作的操作。此操作的返回值將在狀態中可用。
案例展示
import { useFormState} from 'react-dom';
const FormState = () => {
const submitForm = (prevState, queryData) => {
const name = queryData.get("username");
console.log(prevState); // 上一次的from 的state
if(name === '柒八九'){
return {
success: true,
text: "前端開發者"
}
}
else{
return {
success: false,
text: "Error"
}
}
}
const [ message, formAction ] = useFormState(submitForm, null)
return <form action={formAction}>
<label>用戶名</label>
<input type="text" name="username" />
<button>提交</button>
{message && <h1>{message.text}</h1>}
</form>
}
export default FormState;
讓我們簡單解釋一下發生了啥
- submitForm 是負責表單提交的方法。這是一個 Action。
- 在 submitForm 中,我們正在檢查表單的值。
prevState:初始狀態將為 null,之后它將返回表單的 prevState。
queryData:用于獲取此次操作中from表單中對應key的值
useOptimistic() hook
useOptimistic 也新發布的Hook,它允許我們在異步操作時顯示不同的狀態。
這個 hook 將幫助增強用戶體驗,并應該導致更快的響應。這對于需要與服務器交互的應用程序非常有用。
語法
以下是 useOptimistic hook 的語法:
const [ optimisticX, addOptimisticX] = useOptimistic(state, updatefn)
例如,當響應正在返回時,我們可以顯示一個「optimistic狀態」,以便讓用戶獲得即時響應。一旦服務器返回實際響應,optimistic狀態將被替換。
案例展示
import { useOptimistic, useState } from "react";
const Optimistic = () => {
const [messages, setMessages] = useState([
{ text: "初始化信息", sending: false, key: 1 },
]);
const [optimisticMessages, addOptimisticMessage] = useOptimistic(
messages,
(state, newMessage) => [
...state,
{
text: newMessage,
sending: true,
},
]
);
async function sendFormData(formData) {
const sentMessage = await fakeDelayAction(formData.get("message"));
setMessages((messages) => [...messages, { text: sentMessage }]);
}
async function fakeDelayAction(message) {
await new Promise((res) => setTimeout(res, 1000));
return message;
}
const submitData = async (userData) => {
addOptimisticMessage(userData.get("username"));
await sendFormData(userData);
};
return (
<>
{optimisticMessages.map((message, index) => (
<div key={index}>
{message.text}
{!!message.sending && <small> (Sending...)</small>}
</div>
))}
<form action={submitData}>
<h1>OptimisticState Hook</h1>
<div>
<label>Username</label>
<input type="text" name="username" />
</div>
<button type="submit">Submit</button>
</form>
</>
);
};
export default Optimistic;
- fakeDelayAction 模擬一個異步操作。
- submitData 是 action。這個方法負責表單提交。這也可以是 async 的。
- sendFormData 負責將表單發送到 fakeDelayAction
- 設置默認狀態。messages 將用作 useOptimistic() 的輸入,并將返回 optimisticMessages。
const [messages, setMessages] = useState([{ text: "初始化信息", sending: false, key: 1 },]);
在 submitData 內部,我們使用 addOptimisticMessage。這將添加表單數據,以便在 optimisticMessage 中可用。我們將使用此數據在 UI 中顯示消息:
{optimisticMessages.map((message, index) => (
<div key={index}>
{message.text}
{!!message.sending && <small> (Sending...)</small>}
</div>
))}
其實,我們以后在處理類似Form表單狀態時,可以配合Action/useOptimistic/useFormState/useFormState進行狀態的各種流轉處理。
圖片
Reference
[1]React 編譯器_youtube地址:https://youtu.be/kjOacmVsLSE?si=dqCjg0_9x2hOB8BF
[2]React Forget的基本介紹:https://dev.to/usulpro/how-react-forget-will-make-react-usememo-and-usecallback-hooks-absolutely-redundant-4l68
[3]Lit:https://lit.dev/
[4]SEO教程:https://moz.com/beginners-guide-to-seo
[5]react-helmet:https://www.npmjs.com/package/react-helmet