Objavte hook useActionState v Reacte pre zjednodušenú správu stavu spúšťanú asynchrónnymi akciami. Zvýšte efektivitu a používateľský zážitok vašej aplikácie.
Implementácia React useActionState: Správa stavu založená na akciách
Hook useActionState v Reacte, predstavený v nedávnych verziách, ponúka prepracovaný prístup k správe aktualizácií stavu vyplývajúcich z asynchrónnych akcií. Tento mocný nástroj zjednodušuje proces spracovania mutácií, aktualizácie UI a správy chybových stavov, najmä pri práci s React Server Components (RSC) a serverovými akciami. Táto príručka preskúma zložitosti useActionState a poskytne praktické príklady a osvedčené postupy pre implementáciu.
Pochopenie potreby správy stavu založenej na akciách
Tradičná správa stavu v Reacte často zahŕňa oddelenú správu stavov načítavania a chýb v rámci komponentov. Keď akcia (napr. odoslanie formulára, načítanie dát) spustí aktualizáciu stavu, vývojári zvyčajne spravujú tieto stavy pomocou viacerých volaní useState a potenciálne zložitej podmienenej logiky. useActionState poskytuje čistejšie a integrovanejšie riešenie.
Zoberme si jednoduchý scenár odoslania formulára. Bez useActionState by ste mohli mať:
- Stavovú premennú pre dáta formulára.
- Stavovú premennú na sledovanie, či sa formulár odosiela (stav načítavania).
- Stavovú premennú na uchovanie akýchkoľvek chybových správ.
Tento prístup môže viesť k rozsiahlemu kódu a potenciálnym nekonzistentnostiam. useActionState konsoliduje tieto aspekty do jedného hooku, čím zjednodušuje logiku a zlepšuje čitateľnosť kódu.
Predstavenie useActionState
Hook useActionState prijíma dva argumenty:
- Asynchrónnu funkciu („akciu“), ktorá vykonáva aktualizáciu stavu. Môže to byť serverová akcia alebo akákoľvek asynchrónna funkcia.
- Počiatočnú hodnotu stavu.
Vracia pole obsahujúce dva prvky:
- Aktuálnu hodnotu stavu.
- Funkciu na odoslanie akcie. Táto funkcia automaticky spravuje stavy načítavania a chýb spojené s akciou.
Tu je základný príklad:
import { useActionState } from 'react';
async function updateServer(prevState, formData) {
// Simulácia asynchrónnej aktualizácie servera.
await new Promise(resolve => setTimeout(resolve, 1000));
const data = Object.fromEntries(formData);
if (data.name === "error") {
return 'Nepodarilo sa aktualizovať server.';
}
return `Meno aktualizované na: ${data.name}`;
}
function MyComponent() {
const [state, dispatch] = useActionState(updateServer, 'Počiatočný stav');
async function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
const result = await dispatch(formData);
console.log(result);
}
return (
);
}
V tomto príklade:
updateServerje asynchrónna akcia, ktorá simuluje aktualizáciu servera. Prijíma predchádzajúci stav a dáta z formulára.useActionStateinicializuje stav s hodnotou 'Počiatočný stav' a vracia aktuálny stav a funkciudispatch.- Funkcia
handleSubmitvoládispatchs dátami formulára.useActionStateautomaticky spracováva stavy načítavania a chýb počas vykonávania akcie.
Spracovanie stavov načítavania a chýb
Jednou z kľúčových výhod useActionState je jeho vstavaná správa stavov načítavania a chýb. Funkcia dispatch vracia promise, ktorý sa vyrieši s výsledkom akcie. Ak akcia vyhodí chybu, promise sa zamietne s chybou. Toto môžete použiť na zodpovedajúcu aktualizáciu UI.
Upravme predchádzajúci príklad tak, aby zobrazoval správu o načítavaní a chybovú správu:
import { useActionState } from 'react';
import { useState } from 'react';
async function updateServer(prevState, formData) {
// Simulácia asynchrónnej aktualizácie servera.
await new Promise(resolve => setTimeout(resolve, 1000));
const data = Object.fromEntries(formData);
if (data.name === "error") {
throw new Error('Nepodarilo sa aktualizovať server.');
}
return `Meno aktualizované na: ${data.name}`;
}
function MyComponent() {
const [state, dispatch] = useActionState(updateServer, 'Počiatočný stav');
const [isSubmitting, setIsSubmitting] = useState(false);
const [errorMessage, setErrorMessage] = useState(null);
async function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
setIsSubmitting(true);
setErrorMessage(null);
try {
const result = await dispatch(formData);
console.log(result);
} catch (error) {
console.error("Chyba pri odosielaní:", error);
setErrorMessage(error.message);
} finally {
setIsSubmitting(false);
}
}
return (
);
}
Kľúčové zmeny:
- Pridali sme stavové premenné
isSubmittingaerrorMessagena sledovanie stavov načítavania a chýb. - V
handleSubmitnastavímeisSubmittingnatruepred volanímdispatcha zachytávame akékoľvek chyby na aktualizáciuerrorMessage. - Počas odosielania deaktivujeme tlačidlo a podmienečne zobrazujeme správy o načítavaní a chybách.
useActionState so serverovými akciami v React Server Components (RSC)
useActionState exceluje pri použití s React Server Components (RSC) a serverovými akciami. Serverové akcie sú funkcie, ktoré bežia na serveri a môžu priamo meniť dátové zdroje. Umožňujú vám vykonávať operácie na strane servera bez písania API endpointov.
Poznámka: Tento príklad vyžaduje prostredie React nakonfigurované pre Server Components a Server Actions.
// app/actions.js (Serverová akcia)
'use server';
import { cookies } from 'next/headers'; //Príklad, pre Next.js
export async function updateName(prevState, formData) {
const name = formData.get('name');
if (!name) {
return 'Prosím, zadajte meno.';
}
try {
// Simulácia aktualizácie databázy.
await new Promise(resolve => setTimeout(resolve, 1000));
cookies().set('userName', name);
return `Meno aktualizované na: ${name}`; //Úspech!
} catch (error) {
console.error("Aktualizácia databázy zlyhala:", error);
return 'Nepodarilo sa aktualizovať meno.'; // Dôležité: Vráťte správu, nevyhadzujte chybu
}
}
// app/page.jsx (React Server Component)
'use client';
import { useActionState } from 'react';
import { updateName } from './actions';
function MyComponent() {
const [state, dispatch] = useActionState(updateName, 'Počiatočný stav');
async function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
const result = await dispatch(formData);
console.log(result);
}
return (
);
}
export default MyComponent;
V tomto príklade:
updateNameje serverová akcia definovaná vapp/actions.js. Prijíma predchádzajúci stav a dáta formulára, aktualizuje databázu (simulovane) a vracia správu o úspechu alebo chybe. Kľúčové je, že akcia vracia správu namiesto vyhodenia chyby. Serverové akcie uprednostňujú vracanie informatívnych správ.- Komponent je označený ako klientsky komponent (
'use client'), aby mohol používať hookuseActionState. - Funkcia
handleSubmitvoládispatchs dátami formulára.useActionStateautomaticky spravuje aktualizáciu stavu na základe výsledku serverovej akcie.
Dôležité aspekty pre serverové akcie
- Spracovanie chýb v serverových akciách: Namiesto vyhadzovania chýb vráťte z vašej serverovej akcie zmysluplnú chybovú správu.
useActionStatebude túto správu považovať za nový stav. To umožňuje elegantné spracovanie chýb na strane klienta. - Optimistické aktualizácie: Serverové akcie možno použiť s optimistickými aktualizáciami na zlepšenie vnímaného výkonu. Môžete okamžite aktualizovať UI a vrátiť zmenu späť, ak akcia zlyhá.
- Revalidácia: Po úspešnej mutácii zvážte revalidáciu cachovaných dát, aby UI odrážalo najnovší stav.
Pokročilé techniky s useActionState
1. Použitie reducera pre komplexné aktualizácie stavu
Pre zložitejšiu logiku stavu môžete skombinovať useActionState s reducer funkciou. To vám umožní spravovať aktualizácie stavu predvídateľným a udržateľným spôsobom.
import { useActionState } from 'react';
import { useReducer } from 'react';
const initialState = {
count: 0,
message: 'Počiatočný stav',
};
function reducer(state, action) {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
case 'DECREMENT':
return { ...state, count: state.count - 1 };
case 'SET_MESSAGE':
return { ...state, message: action.payload };
default:
return state;
}
}
async function updateState(state, action) {
// Simulácia asynchrónnej operácie.
await new Promise(resolve => setTimeout(resolve, 500));
switch (action.type) {
case 'INCREMENT':
return reducer(state, action);
case 'DECREMENT':
return reducer(state, action);
case 'SET_MESSAGE':
return reducer(state, action);
default:
return state;
}
}
function MyComponent() {
const [state, dispatch] = useActionState(updateState, initialState);
return (
Počet: {state.count}
Správa: {state.message}
);
}
2. Optimistické aktualizácie s useActionState
Optimistické aktualizácie zlepšujú používateľský zážitok tým, že okamžite aktualizujú UI, akoby bola akcia úspešná, a potom vrátia aktualizáciu späť, ak akcia zlyhá. To môže spôsobiť, že vaša aplikácia bude pôsobiť responzívnejšie.
import { useActionState } from 'react';
import { useState } from 'react';
async function updateServer(prevState, formData) {
// Simulácia asynchrónnej aktualizácie servera.
await new Promise(resolve => setTimeout(resolve, 1000));
const data = Object.fromEntries(formData);
if (data.name === "error") {
throw new Error('Nepodarilo sa aktualizovať server.');
}
return `Meno aktualizované na: ${data.name}`;
}
function MyComponent() {
const [name, setName] = useState('Počiatočné meno');
const [state, dispatch] = useActionState(async (prevName, newName) => {
try {
const result = await updateServer(prevName, {
name: newName,
});
return newName; // Aktualizácia pri úspechu
} catch (error) {
// Vrátenie zmeny pri chybe
console.error("Aktualizácia zlyhala:", error);
setName(prevName);
return prevName;
}
}, name);
async function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
const newName = formData.get('name');
setName(newName); // Optimistická aktualizácia UI
await dispatch(newName);
}
return (
);
}
3. Debouncing akcií
V niektorých scenároch možno budete chcieť použiť debouncing akcií, aby ste zabránili ich príliš častému odosielaniu. To môže byť užitočné napríklad pri vyhľadávacích poliach, kde chcete spustiť akciu až potom, čo používateľ prestane písať na určitý čas.
import { useActionState } from 'react';
import { useState, useEffect } from 'react';
async function searchItems(prevState, query) {
// Simulácia asynchrónneho vyhľadávania.
await new Promise(resolve => setTimeout(resolve, 500));
return `Výsledky vyhľadávania pre: ${query}`;
}
function MyComponent() {
const [query, setQuery] = useState('');
const [state, dispatch] = useActionState(searchItems, 'Počiatočný stav');
useEffect(() => {
const timeoutId = setTimeout(() => {
if (query) {
dispatch(query);
}
}, 300); // Debounce na 300ms
return () => clearTimeout(timeoutId);
}, [query, dispatch]);
return (
setQuery(e.target.value)}
/>
Stav: {state}
);
}
Osvedčené postupy pre useActionState
- Udržujte akcie čisté: Uistite sa, že vaše akcie sú čisté funkcie (alebo čo najbližšie k nim). Nemali by mať vedľajšie účinky okrem aktualizácie stavu.
- Spracovávajte chyby elegantne: Vždy spracovávajte chyby vo vašich akciách a poskytujte používateľovi informatívne chybové správy. Ako bolo uvedené vyššie pri serverových akciách, uprednostnite vrátenie chybovej správy zo serverovej akcie namiesto vyhadzovania chyby.
- Optimalizujte výkon: Dávajte pozor na výkonnostné dôsledky vašich akcií, najmä pri práci s veľkými dátovými sadami. Zvážte použitie memoizačných techník na zabránenie zbytočným prekresleniam.
- Zvážte prístupnosť: Uistite sa, že vaša aplikácia zostáva prístupná pre všetkých používateľov, vrátane tých so zdravotným postihnutím. Poskytnite vhodné ARIA atribúty a navigáciu pomocou klávesnice.
- Dôkladné testovanie: Píšte jednotkové a integračné testy, aby ste sa uistili, že vaše akcie a aktualizácie stavu fungujú správne.
- Internacionalizácia (i18n): Pre globálne aplikácie implementujte i18n na podporu viacerých jazykov a kultúr.
- Lokalizácia (l10n): Prispôsobte svoju aplikáciu špecifickým lokalitám poskytovaním lokalizovaného obsahu, formátov dátumov a symbolov mien.
useActionState vs. iné riešenia pre správu stavu
Hoci useActionState poskytuje pohodlný spôsob spravovania aktualizácií stavu založených na akciách, nenahrádza všetky riešenia pre správu stavu. Pre zložité aplikácie s globálnym stavom, ktorý je potrebné zdieľať medzi viacerými komponentmi, môžu byť vhodnejšie knižnice ako Redux, Zustand alebo Jotai.
Kedy použiť useActionState:
- Jednoduché až stredne zložité aktualizácie stavu.
- Aktualizácie stavu úzko spojené s asynchrónnymi akciami.
- Integrácia s React Server Components a Server Actions.
Kedy zvážiť iné riešenia:
- Komplexná správa globálneho stavu.
- Stav, ktorý je potrebné zdieľať medzi veľkým počtom komponentov.
- Pokročilé funkcie ako time-travel debugging alebo middleware.
Záver
Hook useActionState v Reacte ponúka mocný a elegantný spôsob spravovania aktualizácií stavu spúšťaných asynchrónnymi akciami. Konsolidáciou stavov načítavania a chýb zjednodušuje kód a zlepšuje čitateľnosť, najmä pri práci s React Server Components a serverovými akciami. Pochopenie jeho silných a slabých stránok vám umožní zvoliť správny prístup k správe stavu pre vašu aplikáciu, čo vedie k udržateľnejšiemu a efektívnejšiemu kódu.
Dodržiavaním osvedčených postupov uvedených v tejto príručke môžete efektívne využiť useActionState na zlepšenie používateľského zážitku a vývojového workflow vašej aplikácie. Nezabudnite zvážiť zložitosť vašej aplikácie a zvoliť riešenie pre správu stavu, ktoré najlepšie vyhovuje vašim potrebám. Od jednoduchých odoslaní formulárov po zložité dátové mutácie, useActionState môže byť cenným nástrojom vo vašom arzenáli pre vývoj v Reacte.