React19 新增Hooks中useOptimistic的使用
概念
官方文檔上介紹:是一個(gè)可以幫助你更樂(lè)觀地更新用戶界面 的Hooks,實(shí)際上 有點(diǎn)像 loading 的過(guò)渡效果,在異步操作的時(shí)候先顯示一個(gè)樂(lè)觀的結(jié)果(即我們提前指定的內(nèi)容),
如果異步操作成功,再更新成我們預(yù)期的內(nèi)容,如果異步操作失敗,那么之前樂(lè)觀的結(jié)果需要被撤銷(xiāo),用戶界面要恢復(fù)到異步操作開(kāi)始之前的狀態(tài)。這樣用戶界面看起來(lái)會(huì)更流暢,用戶體驗(yàn)更好。
例如,用戶在文章下方發(fā)表評(píng)論,當(dāng)點(diǎn)擊發(fā)送按鈕時(shí),界面會(huì)立即顯示為已發(fā)送狀態(tài),并將評(píng)論內(nèi)容添加到評(píng)論列表中,不需要等待服務(wù)器的響應(yīng),這個(gè)時(shí)候顯示的是一個(gè)樂(lè)觀的結(jié)果。如果評(píng)論發(fā)送成功,那么之前樂(lè)觀更新的狀態(tài)會(huì)被保留,界面將繼續(xù)顯示為已發(fā)送狀態(tài),評(píng)論內(nèi)容也會(huì)保持在評(píng)論列表中。如果評(píng)論發(fā)送失敗,那么之前樂(lè)觀更新的狀態(tài)需要被撤銷(xiāo)。界面需要回滾到未發(fā)送狀態(tài),并從評(píng)論列表中移除剛才添加的評(píng)論內(nèi)容。
我覺(jué)得有一部分有點(diǎn)類(lèi)似錯(cuò)誤邊界的感覺(jué),但錯(cuò)誤邊界 是出現(xiàn)錯(cuò)誤之后才顯示備用內(nèi)容,而 useOptimistic 是異步結(jié)果返回之前顯示樂(lè)觀內(nèi)容。
用法
const [optimisticState, addOptimistic] = useOptimistic(
state,
// 更新函數(shù)
(currentState, optimisticValue) => {
// 使用樂(lè)觀值
// 合并并返回新 state
}
);
state:是初始的狀態(tài),也就是樂(lè)觀結(jié)果之前的狀態(tài)updateFn:是更新函數(shù)
參數(shù)
當(dāng)前 state (即currentState ) 和傳遞給 addOptimistic 的值 (即optimisticValue),
返回值optimisticState:如果異步操作開(kāi)始或成功,等于currentState 和 optimisticValue 的合并值,其他情況下(不成功或者掛起)都等于stateaddOptimistic:觸發(fā) optimisticState 更新的函數(shù),通過(guò)調(diào)用addOptimistic 進(jìn)而調(diào)用內(nèi)部的 updateFn
效果
useOptimistic Hooks實(shí)現(xiàn)效果
//App.js
import { useOptimistic, useState, useRef, startTransition } from "react";
// 模擬異步請(qǐng)求函數(shù)
const mockCommentRequest = async (message) => {
await new Promise((resolve, reject) => {
setTimeout(() => {
// 模擬請(qǐng)求成功或失敗
const isSuccess = Math.random() > 0.5;
if (isSuccess) {
resolve({ success: true, message: '成功' });
} else {
reject({ success: false, message: '失敗' });
}
}, 1000);
});
return message;
};
function Thread({ messages, sendMessageAction }) {
const formRef = useRef();
const [optimisticMessages, addOptimisticMessage] = useOptimistic(
messages,
(state, newMessage) => {
// console.log(state, newMessage,'-------------')
return [
{
text: newMessage,
sending: true
},
...state,
]
}
);
function formAction(formData) {
const message = formData.get("message");
// 不管異步結(jié)果,先進(jìn)行樂(lè)觀更新
addOptimisticMessage(message);
formRef.current.reset();
//執(zhí)行異步操作
startTransition(async () => {
await sendMessageAction(message);
});
}
return (
<>
<form action={formAction} ref={formRef}>
<input type="text" name="message" placeholder="發(fā)送評(píng)論" />
<button type="submit">發(fā)送</button>
</form>
{optimisticMessages.map((message, index) => (
<div key={index}>
{message.text}
{message.sending && <small>(發(fā)送中……)</small>}
</div>
))}
</>
);
}
export default function App() {
const [messages, setMessages] = useState([
{ text: "評(píng)論1", sending: false, key: 1 },
{ text: "評(píng)論2", sending: false, key: 2 },
]);
async function sendMessageAction(message) {
try {
const sentMessage = await mockCommentRequest(message);
startTransition(() => {
setMessages((messages) => [
{ text: sentMessage, sending: false },
...messages
]);
});
} catch (error) {
console.error('發(fā)送失敗:', error.message);
// 可以在這里處理發(fā)送失敗的情況,例如顯示錯(cuò)誤提示
}
}
return <Thread messages={messages} sendMessageAction={sendMessageAction} />;
}
思考
1. 在這個(gè)Hooks出現(xiàn)之前,我們?nèi)绾螌?shí)現(xiàn)類(lèi)似的效果的呢?
useOptimistic 之前,我們需要手動(dòng)管理狀態(tài)來(lái)模擬樂(lè)觀更新和回滾。在實(shí)現(xiàn)上,首先把數(shù)據(jù)添加到顯示數(shù)組,實(shí)現(xiàn)樂(lè)觀更新,如果異步操作成功,替換成真實(shí)發(fā)送的消息,如果失敗,從顯示數(shù)組中移除樂(lè)觀消息,相當(dāng)于手動(dòng)回滾到操作前的狀態(tài)。
function Thread({ messages, sendMessageAction }) {
const formRef = useRef();
const [displayMessages, setDisplayMessages] = useState(messages);
async function formAction(formData) {
const message = formData.get("message");
const tempId = Date.now();
// 1. 樂(lè)觀更新
setDisplayMessages(prev => [
{ id: tempId, text: message, sending: true },
...prev
]);
formRef.current.reset();
try {
// 2. 實(shí)際發(fā)送
const sentMessage = await sendMessageAction(message);
// 3. 替換樂(lè)觀消息為實(shí)際消息
setDisplayMessages(prev => [
{ text: sentMessage, sending: false },
...prev.filter(msg => msg.id !== tempId)
]);
} catch (error) {
// 4. 失敗時(shí)移除樂(lè)觀消息
setDisplayMessages(prev => prev.filter(msg => msg.id !== tempId));
console.error('發(fā)送失敗:', error.message);
}
}
return (
<>
<form action={formAction} ref={formRef}>
<input type="text" name="message" placeholder="發(fā)送評(píng)論" />
<button type="submit">發(fā)送</button>
</form>
{displayMessages.map((message,index) => (
<div key={index}>
{message.text}
{message.sending && <small>(發(fā)送中……)</small>}
</div>
))}
</>
);
}
2. useOptimistic 相比于之前的實(shí)現(xiàn) 有什么優(yōu)勢(shì)嗎?
- 簡(jiǎn)化狀態(tài)管理:可以幫助我們自動(dòng)回滾到原來(lái)的狀態(tài),不需要手動(dòng)回滾
- 邏輯分離:把樂(lè)觀更新的邏輯和異步操作的邏輯分離,使得代碼結(jié)構(gòu)更清晰。開(kāi)發(fā)者可以專(zhuān)注于異步操作的實(shí)現(xiàn),而不必過(guò)多關(guān)注狀態(tài)管理的細(xì)節(jié)。
到此這篇關(guān)于React19 新增Hooks中useOptimistic的使用的文章就介紹到這了,更多相關(guān)React19 新增 useOptimistic內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于React Context實(shí)現(xiàn)一個(gè)簡(jiǎn)單的狀態(tài)管理的示例代碼
本文主要介紹了基于React Context實(shí)現(xiàn)一個(gè)簡(jiǎn)單的狀態(tài)管理的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
React性能優(yōu)化三劍客之useMemo、memo與useCallback詳解
useMemo和useCallback是React 中用于性能優(yōu)化的兩個(gè)重要 Hook,它們基于相同的依賴(lài)項(xiàng)比較機(jī)制,但適用場(chǎng)景不同,這篇文章主要介紹了React性能優(yōu)化三劍客之useMemo、memo與useCallback的相關(guān)資料,需要的朋友可以參考下2026-04-04
ReactNative中使用Redux架構(gòu)總結(jié)
本篇文章主要介紹了ReactNative中使用Redux架構(gòu)總結(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
React Antd中如何設(shè)置表單只輸入數(shù)字
這篇文章主要介紹了React Antd中如何設(shè)置表單只輸入數(shù)字問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
詳解如何使用React和MUI創(chuàng)建多選Checkbox樹(shù)組件
這篇文章主要為大家詳細(xì)介紹了如何使用 React 和 MUI(Material-UI)庫(kù)來(lái)創(chuàng)建一個(gè)多選 Checkbox 樹(shù)組件,該組件可以用于展示樹(shù)形結(jié)構(gòu)的數(shù)據(jù),并允許用戶選擇多個(gè)節(jié)點(diǎn),感興趣的可以了解下2024-01-01
React 如何使用時(shí)間戳計(jì)算得到開(kāi)始和結(jié)束時(shí)間戳
這篇文章主要介紹了React 如何拿時(shí)間戳計(jì)算得到開(kāi)始和結(jié)束時(shí)間戳,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09
淺析history 和 react-router 的實(shí)現(xiàn)原理
react-router 版本更新非???但是它的底層實(shí)現(xiàn)原理確是萬(wàn)變不離其中,在本文中會(huì)從前端路由出發(fā)到 react-router 原理總結(jié)與分享,本文對(duì)history 和 react-router實(shí)現(xiàn)原理講解的非常詳細(xì),需要的朋友跟隨小編一起看看吧2023-08-08
探討JWT身份校驗(yàn)與React-router無(wú)縫集成
這篇文章主要為大家介紹了JWT身份校驗(yàn)與React-router無(wú)縫集成的探討解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06

