Prozkoumejte streamování odpovědí z React Server Actions pro progresivní odezvu formulářů. Naučte se, jak vytvářet rychlejší a responzivnější formuláře pro lepší uživatelský zážitek.
Streamování odpovědí z React Server Actions: Progresivní odezva formuláře pro vylepšené UX
React Server Actions přinášejí zásadní změnu paradigmatu v tom, jak zpracováváme operace na straně serveru v našich React aplikacích. Jednou z nejzajímavějších funkcí je schopnost streamovat odpovědi progresivně, což nám umožňuje poskytovat uživatelům okamžitou zpětnou vazbu ještě před dokončením celé operace. To je zvláště výhodné pro formuláře, kde můžeme vytvořit responzivnější a poutavější uživatelský zážitek aktualizací UI, jakmile jsou data k dispozici.
Pochopení React Server Actions
Server Actions jsou asynchronní funkce, které běží na serveru a jsou iniciovány z React komponent. Nabízejí několik výhod oproti tradičním voláním API:
- Zvýšená bezpečnost: Server Actions běží přímo na serveru, což snižuje riziko odhalení citlivých dat nebo logiky klientovi.
- Méně opakujícího se kódu: Odstraňují potřebu samostatných API tras a logiky pro načítání dat na straně klienta.
- Vylepšený výkon: Mohou využívat server-side rendering (SSR) a cachování pro rychlejší počáteční načítání a lepší výkon.
- Typová bezpečnost: S TypeScriptem poskytují Server Actions end-to-end typovou bezpečnost, což zajišťuje konzistenci dat mezi klientem a serverem.
Síla streamování odpovědí
Tradiční odesílání formulářů často zahrnuje odeslání všech dat na server, čekání na odpověď a následnou aktualizaci UI. To může vést k vnímanému zpoždění, zejména u složitých formulářů nebo pomalého síťového připojení. Streamování odpovědí umožňuje serveru posílat data zpět klientovi po částech, což nám umožňuje progresivně aktualizovat UI, jakmile jsou data k dispozici.
Představte si formulář, který vypočítává složitou cenu na základě vstupu uživatele. Místo čekání na dokončení celého výpočtu může server streamovat průběžné výsledky zpět klientovi a poskytovat tak uživateli zpětnou vazbu v reálném čase. To může výrazně zlepšit uživatelský zážitek a aplikace bude působit responzivněji.
Implementace progresivní odezvy formuláře pomocí Server Actions
Pojďme si projít příklad, jak implementovat progresivní odezvu formuláře pomocí React Server Actions.
Příklad: Převodník měn v reálném čase
Vytvoříme jednoduchý formulář pro převod měn, který poskytuje aktualizace směnného kurzu v reálném čase, jak uživatel zadává částku.
1. Nastavení Server Action
Nejprve definujeme Server Action, která se stará o převod měny.
// server/actions.ts
'use server';
import { unstable_cache } from 'next/cache';
async function getExchangeRate(fromCurrency: string, toCurrency: string): Promise<number> {
// Simulace načítání směnného kurzu z externího API
console.log(`Fetching exchange rate for ${fromCurrency} to ${toCurrency}`);
await new Promise(resolve => setTimeout(resolve, 500)); // Simulace zpoždění sítě
if (fromCurrency === 'USD' && toCurrency === 'EUR') return 0.92;
if (fromCurrency === 'EUR' && toCurrency === 'USD') return 1.09;
if (fromCurrency === 'USD' && toCurrency === 'JPY') return 145;
if (fromCurrency === 'JPY' && toCurrency === 'USD') return 0.0069;
throw new Error(`Směnný kurz pro ${fromCurrency} na ${toCurrency} nebyl nalezen`);
}
export const convertCurrency = async (prevState: any, formData: FormData) => {
const fromCurrency = formData.get('fromCurrency') as string;
const toCurrency = formData.get('toCurrency') as string;
const amount = Number(formData.get('amount'));
try {
if (!fromCurrency || !toCurrency || isNaN(amount)) {
return { message: 'Prosím, zadejte platný vstup.' };
}
// Simulace streamování odpovědi
await new Promise(resolve => setTimeout(resolve, 250));
const exchangeRate = await unstable_cache(
async () => getExchangeRate(fromCurrency, toCurrency),
[`exchange-rate-${fromCurrency}-${toCurrency}`],
{ tags: [`exchange-rate-${fromCurrency}-${toCurrency}`] }
)();
await new Promise(resolve => setTimeout(resolve, 250));
const convertedAmount = amount * exchangeRate;
return { message: `Přepočtená částka: ${convertedAmount.toFixed(2)} ${toCurrency}` };
} catch (e: any) {
console.error(e);
return { message: 'Převod měny se nezdařil.' };
}
};
V tomto příkladu Server Action convertCurrency
načítá směnný kurz (simulovaný se zpožděním) a vypočítává převedenou částku. Přidali jsme umělá zpoždění pomocí setTimeout
, abychom simulovali latenci sítě a demonstrovali efekt streamování.
2. Implementace React komponenty
Dále vytvoříme React komponentu, která používá Server Action.
// app/page.tsx
'use client';
import { useState, useTransition } from 'react';
import { convertCurrency } from './server/actions';
import { useFormState } from 'react-dom';
export default function CurrencyConverter() {
const [fromCurrency, setFromCurrency] = useState('USD');
const [toCurrency, setToCurrency] = useState('EUR');
const [amount, setAmount] = useState('');
const [isPending, startTransition] = useTransition();
const [state, formAction] = useFormState(convertCurrency, { message: '' });
const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault();
startTransition(() => {
formAction(new FormData(event.target as HTMLFormElement));
});
};
return (
<div>
<h2>Převodník měn v reálném čase</h2>
<form action={handleSubmit}>
<label htmlFor="fromCurrency">Z:</label>
<select id="fromCurrency" name="fromCurrency" value={fromCurrency} onChange={(e) => setFromCurrency(e.target.value)}>
<option value="USD">USD</option>
<option value="EUR">EUR</option>
<option value="JPY">JPY</option>
</select>
<label htmlFor="toCurrency">Do:</label>
<select id="toCurrency" name="toCurrency" value={toCurrency} onChange={(e) => setToCurrency(e.target.value)}>
<option value="EUR">EUR</option>
<option value="USD">USD</option>
<option value="JPY">JPY</option>
</select>
<label htmlFor="amount">Částka:</label>
<input
type="number"
id="amount"
name="amount"
value={amount}
onChange={(e) => setAmount(e.target.value)}
/>
<button type="submit" disabled={isPending}>
{isPending ? 'Převádím...' : 'Převést'}
</button>
</form>
<p>{state.message}</p>
</div>
);
}
Klíčové body:
- Používáme hook
useFormState
ke správě stavu formuláře a volání Server Action. - Stav
isPending
zuseTransition
deaktivuje tlačítko pro odeslání a zobrazuje zprávu "Převádím...", zatímco akce běží, což dává uživateli zpětnou vazbu. - Funkce
formAction
vrácená hookemuseFormState
automaticky zpracovává odeslání formuláře a aktualizuje stav odpovědí ze Server Action.
3. Pochopení progresivních aktualizací
Když uživatel odešle formulář, zavolá se funkce handleSubmit
. Vytvoří objekt FormData
z formuláře a předá ho funkci formAction
. Server Action se poté provede na serveru. Díky umělým zpožděním zavedeným v Server Action si všimnete následujícího:
- Tlačítko pro odeslání se téměř okamžitě změní na "Převádím...".
- Po krátkém zpoždění (250 ms) kód simuluje získání směnného kurzu.
- Přepočtená částka je vypočítána a výsledek je odeslán zpět klientovi.
state.message
v React komponentě je aktualizován a zobrazuje přepočtenou částku.
To ukazuje, jak nám streamování odpovědí umožňuje poskytovat uživateli průběžné aktualizace, jakmile jsou data k dispozici, což vede k responzivnějšímu a poutavějšímu uživatelskému zážitku.
Výhody progresivní odezvy formuláře
- Vylepšený uživatelský zážitek: Poskytuje uživatelům okamžitou zpětnou vazbu, díky čemuž aplikace působí responzivněji a méně pomale.
- Snížená vnímaná latence: Zobrazováním průběžných výsledků uživatelé vnímají proces jako rychlejší, i když celková operace trvá stejně dlouho.
- Zvýšená angažovanost: Udržuje uživatele v zapojení poskytováním aktualizací v reálném čase a zabraňuje jim opustit formulář kvůli vnímaným zpožděním.
- Zvýšené konverzní poměry: Plynulejší a responzivnější uživatelský zážitek může vést k vyšším konverzním poměrům, zejména u složitých formulářů.
Pokročilé techniky
1. Použití `useOptimistic` pro okamžité aktualizace UI
Hook useOptimistic
vám umožňuje optimisticky aktualizovat UI ještě před dokončením Server Action. To může poskytnout ještě rychlejší vnímanou dobu odezvy, protože UI okamžitě odráží očekávaný výsledek.
import { useOptimistic } from 'react';
function MyComponent() {
const [optimisticState, addOptimistic] = useOptimistic(
initialState,
(state, newUpdate) => {
// Vraťte nový stav na základě aktualizace
return { ...state, ...newUpdate };
}
);
const handleClick = async () => {
addOptimistic({ someValue: 'optimistic update' });
await myServerAction();
};
return (
<div>
<p>{optimisticState.someValue}</p>
<button onClick={handleClick}>Aktualizovat</button>
</div>
);
}
V příkladu s převodníkem měn byste mohli optimisticky aktualizovat převedenou částku na základě aktuálního směnného kurzu, což by uživateli poskytlo okamžitý náhled předtím, než se skutečný výpočet na serveru dokončí. Pokud server vrátí chybu, můžete optimistickou aktualizaci vrátit zpět.
2. Implementace zpracování chyb a záložních mechanismů
Je klíčové implementovat robustní zpracování chyb a záložní mechanismy pro případy, kdy Server Action selže nebo je přerušeno síťové připojení. Můžete použít blok try...catch
v rámci Server Action k zachycení chyb a vrácení příslušné chybové zprávy klientovi.
// server/actions.ts
export const convertCurrency = async (prevState: any, formData: FormData) => {
// ...
try {
// ...
} catch (error: any) {
console.error(error);
return { message: 'Při převodu měny došlo k chybě. Zkuste to prosím později znovu.' };
}
};
Na straně klienta můžete uživateli zobrazit chybovou zprávu a poskytnout možnosti pro opakování operace nebo kontaktování podpory.
3. Cachování směnných kurzů pro zvýšení výkonu
Načítání směnných kurzů z externího API může být úzkým hrdlem výkonu. Pro zlepšení výkonu můžete směnné kurzy cachovat pomocí mechanismu jako Redis nebo Memcached. Funkce unstable_cache
z Next.js (jak je použita v příkladu) poskytuje vestavěné řešení cachování. Nezapomeňte pravidelně invalidovat cache, abyste zajistili, že směnné kurzy jsou aktuální.
4. Aspekty internacionalizace
Při vytváření aplikací pro globální publikum je důležité zvážit internacionalizaci (i18n). To zahrnuje:
- Formátování čísel: Používejte vhodné formáty čísel pro různé lokalizace (např. použití čárek nebo teček jako desetinných oddělovačů).
- Formátování měny: Zobrazujte symboly a formáty měn podle lokalizace uživatele.
- Formátování data a času: Používejte vhodné formáty data a času pro různé lokalizace.
- Lokalizace: Překládejte UI do různých jazyků.
Knihovny jako Intl
a react-intl
vám mohou pomoci s implementací i18n ve vašich React aplikacích.
Příklady a případy použití z reálného světa
- E-commerce: Zobrazování nákladů na dopravu a odhadů doručení v reálném čase, jak uživatel přidává položky do košíku.
- Finanční aplikace: Poskytování kurzů akcií a aktualizací portfolia v reálném čase.
- Rezervace cestování: Zobrazování cen a dostupnosti letů v reálném čase.
- Vizualizace dat: Streamování aktualizací dat do grafů a diagramů.
- Nástroje pro spolupráci: Zobrazování aktualizací dokumentů a projektů v reálném čase.
Závěr
Streamování odpovědí z React Server Action nabízí mocný způsob, jak vylepšit uživatelský zážitek vašich React aplikací. Poskytováním progresivních odpovědí formulářů můžete vytvářet rychlejší, responzivnější a poutavější formuláře, které udrží uživatele v zapojení a zlepší konverzní poměry. Kombinací streamování odpovědí s technikami jako jsou optimistické aktualizace a cachování můžete vytvořit skutečně výjimečné uživatelské zážitky.
Jak se React Server Actions dále vyvíjejí, můžeme očekávat ještě výkonnější funkce a možnosti, které dále zjednoduší vývoj složitých a dynamických webových aplikací.
Další zdroje
Tato příručka poskytuje komplexní přehled streamování odpovědí z React Server Action a jeho aplikace na progresivní odezvu formulářů. Porozuměním zde diskutovaným konceptům a technikám můžete využít tuto mocnou funkci k vytváření rychlejších, responzivnějších a poutavějších webových aplikací.