React全新實驗性Hooks:UseOptimistic、UseFormStatus
近日,React 中引入了兩個實驗性 Hooks:useOptimistic 和 useFormStatus,下面就分別來這兩個 Hooks 都有什么用處!
useOptimistic
實驗性 useOptimistic Hooks 提供了一種在應(yīng)用中實現(xiàn)樂觀更新的方法。樂觀更新是一種通過使應(yīng)用看起來響應(yīng)更快來增強(qiáng)用戶體驗的技術(shù)。
在實際場景中,往往會遇到一些需要與服務(wù)器進(jìn)行異步交互的情況,比如消息發(fā)送。為了提升用戶體驗,在這類操作中,我們通常希望優(yōu)先顯示新數(shù)據(jù)或新狀態(tài),而不是等待服務(wù)器返回響應(yīng)后再進(jìn)行更新。這樣做可以讓用戶立即感知到自己的操作已經(jīng)被執(zhí)行,降低等待時間和不確定性。
useOptimistic 鉤子就是為了支持這種優(yōu)化而設(shè)計的。當(dāng)組件通過該鉤子創(chuàng)建一個新狀態(tài)時,可以指定一個函數(shù),用于在每次更新狀態(tài)時生成一個新的狀態(tài)數(shù)組。這個函數(shù)可以在新狀態(tài)中添加一些臨時數(shù)據(jù),比如正在發(fā)送的消息等。同時,將這些臨時數(shù)據(jù)展示給用戶,使其可以及時地感知到自己的操作已經(jīng)被執(zhí)行,從而提高交互體驗。
來看下面的例子:
import { experimental_useOptimistic as useOptimistic } from 'react';
import { send } from './_actions.js';
export function Thread({ messages }) {
const [optimisticMessages, addOptimisticMessage] = useOptimistic(
messages,
(state, newMessage) => [...state, { message: newMessage, sending: true }],
);
const formRef = useRef();
return (
<div>
{optimisticMessages.map((m) => (
<div>
{m.message}
{m.sending ? 'Sending...' : ''}
</div>
))}
<form
action={async (formData) => {
const message = formData.get('message');
formRef.current.reset();
addOptimisticMessage(message);
await send(message);
}}
ref={formRef}
>
<input type="text" name="message" />
</form>
</div>
);
}
這段代碼實現(xiàn)了消息展示和發(fā)送功能。
- 首先定義了一個名為Thread的組件,其接收一個名為messages的屬性作為輸入,用于展示當(dāng)前線程所有消息。
- 接下來,通過useOptimistic鉤子,創(chuàng)建了一個名為optimisticMessages的新狀態(tài)和一個名為addOptimisticMessage的回調(diào)函數(shù),用于在表單提交前更新消息列表,并支持樂觀地添加一條新消息到列表中,同時會顯示"Sending..."字樣,表示正在發(fā)送中。
- 最后,返回了包含了消息列表和消息發(fā)送表單的元素。其中,使用了Array.map()方法遍歷optimisticMessages狀態(tài),渲染出每一條消息以及可能的"Sending..."字樣。表單元素則使用<input>標(biāo)簽定義文本輸入框,將用戶輸入的消息內(nèi)容傳遞給send()方法,并且當(dāng)表單提交時,調(diào)用了addOptimisticMessage()回調(diào)函數(shù),將輸入的消息添加到消息列表中進(jìn)行展示,并在待發(fā)送狀態(tài)時顯示"Sending..."字樣。
這就是上面提到的樂觀更新,即在消息發(fā)送過程中可以先預(yù)期顯示該條消息,這樣可以使用戶的操作感受更加流暢。
useFormStatus
實驗性 useFormStatus Hook 可以在表單操作中使用,它提供了 pending 屬性。
import { experimental_useFormStatus as useFormStatus } from 'react-dom';
function Submit() {
const { pending } = useFormStatus();
return (
<input
type="submit"
className={pending ? 'button-pending' : 'button-normal'}
disabled={pending}
>
提交
</input>
);
}
這段代碼使用了實驗性的 useFormStatus Hook,它從 react-dom 庫中導(dǎo)入。useFormStatus Hook 可以在表單操作(比如提交、重置等)中使用,提供了一個 pending 屬性,表示當(dāng)前是否正在處理中。在這段代碼中,將 pending 屬性用于控制 <input> 元素的 className 和 disabled 屬性。
除此之外,useFormStatus 還提供了 data, action, method 屬性:
const {pending, data, action, method} = useFormStatus();
useFormStatus Hook 可以用于實現(xiàn)加載指示器等功能??梢园阉?dāng)作使用 useTransition Hook 實現(xiàn)加載狀態(tài)的一種快捷方式。目前,該 Hook 僅在實驗性通道中提供,會在接近穩(wěn)定版本發(fā)布時分享文檔。它內(nèi)部實現(xiàn)使用 startTransition 和 context 對象。這是理解其行為的一種好方法,但實際的實現(xiàn)細(xì)節(jié)未來可能會有所改變。