Ištirkite React 'useActionState' su būsenų mašinomis, kad sukurtumėte patikimas ir nuspėjamas vartotojo sąsajas. Išmokite veiksmų būsenų perėjimo logikos sudėtingoms programoms.
React useActionState būsenų mašina: Veiksmų būsenų perėjimo logikos įvaldymas
React useActionState
yra galingas „hook“, pristatytas React 19 versijoje (šiuo metu „canary“ stadijoje), skirtas supaprastinti asinchroninius būsenos atnaujinimus, ypač dirbant su serverio veiksmais. Sujungus jį su būsenų mašina, jis suteikia elegantišką ir patikimą būdą valdyti sudėtingas vartotojo sąsajos sąveikas ir būsenų perėjimus. Šiame tinklaraščio įraše gilinsimės į tai, kaip efektyviai panaudoti useActionState
su būsenų mašina, norint kurti nuspėjamas ir lengvai palaikomas React programas.
Kas yra būsenų mašina?
Būsenų mašina yra matematinis skaičiavimo modelis, aprašantis sistemos elgesį kaip baigtinį skaičių būsenų ir perėjimų tarp tų būsenų. Kiekviena būsena atspindi atskirą sistemos sąlygą, o perėjimai atspindi įvykius, kurie priverčia sistemą pereiti iš vienos būsenos į kitą. Pagalvokite apie tai kaip apie eigos schemą, bet su griežtesnėmis taisyklėmis, kaip galima judėti tarp žingsnių.
Būsenų mašinos naudojimas jūsų React programoje suteikia keletą privalumų:
- Nuspėjamumas: Būsenų mašinos užtikrina aiškų ir nuspėjamą kontrolės srautą, todėl lengviau suprasti jūsų programos elgseną.
- Palaikomumas: Atskyrus būsenos logiką nuo vartotojo sąsajos atvaizdavimo, būsenų mašinos pagerina kodo organizavimą ir palengvina programos palaikymą bei atnaujinimą.
- Testuojamumas: Būsenų mašinos yra iš prigimties testuojamos, nes galite lengvai apibrėžti laukiamą elgseną kiekvienai būsenai ir perėjimui.
- Vizualinis atvaizdavimas: Būsenų mašinas galima atvaizduoti vizualiai, o tai padeda komunikuoti programos elgseną kitiems programuotojams ar suinteresuotosioms šalims.
Pristatome useActionState
useActionState
„hook“ leidžia jums valdyti veiksmo, kuris potencialiai keičia programos būseną, rezultatą. Jis sukurtas sklandžiai veikti su serverio veiksmais, bet gali būti pritaikytas ir kliento pusės veiksmams. Jis suteikia švarų būdą valdyti krovimo būsenas, klaidas ir galutinį veiksmo rezultatą, palengvindamas reaguojančių ir vartotojui draugiškų sąsajų kūrimą.
Štai pagrindinis pavyzdys, kaip naudojamas useActionState
:
const [state, dispatch] = useActionState(async (prevState, formData) => {
// Jūsų veiksmo logika čia
try {
const result = await someAsyncFunction(formData);
return { ...prevState, data: result };
} catch (error) {
return { ...prevState, error: error.message };
}
}, { data: null, error: null });
Šiame pavyzdyje:
- Pirmasis argumentas yra asinchroninė funkcija, kuri atlieka veiksmą. Ji gauna ankstesnę būseną ir formos duomenis (jei taikoma).
- Antrasis argumentas yra pradinė būsena.
- „Hook“ grąžina masyvą, kuriame yra dabartinė būsena ir „dispatch“ funkcija.
useActionState
ir būsenų mašinų derinimas
Tikroji galia atsiskleidžia sujungus useActionState
su būsenų mašina. Tai leidžia apibrėžti sudėtingus būsenos perėjimus, kuriuos sukelia asinchroniniai veiksmai. Apsvarstykime scenarijų: paprastas el. prekybos komponentas, kuris gauna produkto informaciją.
Pavyzdys: Produkto informacijos gavimas
Mes apibrėšime šias būsenas mūsų produkto informacijos komponentui:
- Idle (Laukimas): Pradinė būsena. Produkto informacija dar nebuvo gauta.
- Loading (Kraunama): Būsena, kol gaunama produkto informacija.
- Success (Sėkmė): Būsena, kai produkto informacija sėkmingai gauta.
- Error (Klaida): Būsena, jei gaunant produkto informaciją įvyko klaida.
Šią būsenų mašiną galime pavaizduoti naudodami objektą:
const productDetailsMachine = {
initial: 'idle',
states: {
idle: {
on: {
FETCH: 'loading',
},
},
loading: {
on: {
SUCCESS: 'success',
ERROR: 'error',
},
},
success: {
type: 'final',
},
error: {
on: {
FETCH: 'loading',
},
},
},
};
Tai supaprastintas vaizdas; bibliotekos, tokios kaip XState, siūlo sudėtingesnes būsenų mašinų implementacijas su tokiomis funkcijomis kaip hierarchinės būsenos, lygiagrečios būsenos ir apsaugos (guards).
React implementacija
Dabar integruokime šią būsenų mašiną su useActionState
React komponente.
import React from 'react';
// Įdiekite XState, jei norite pilnos būsenų mašinos patirties. Šiam paprastam pavyzdžiui naudosime paprastą objektą.
// import { createMachine, useMachine } from 'xstate';
const productDetailsMachine = {
initial: 'idle',
states: {
idle: {
on: {
FETCH: 'loading',
},
},
loading: {
on: {
SUCCESS: 'success',
ERROR: 'error',
},
},
success: {
type: 'final',
},
error: {
on: {
FETCH: 'loading',
},
},
},
};
function ProductDetails({ productId }) {
const [state, dispatch] = React.useReducer(
(state, event) => {
const nextState = productDetailsMachine.states[state].on[event];
return nextState || state; // Grąžinti kitą būseną arba dabartinę, jei perėjimas neapibrėžtas
},
productDetailsMachine.initial
);
const [productData, setProductData] = React.useState(null);
const [error, setError] = React.useState(null);
React.useEffect(() => {
if (state === 'loading') {
const fetchData = async () => {
try {
const response = await fetch(`https://api.example.com/products/${productId}`); // Pakeiskite savo API galiniu tašku
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setProductData(data);
setError(null);
dispatch('SUCCESS');
} catch (e) {
setError(e.message);
setProductData(null);
dispatch('ERROR');
}
};
fetchData();
}
}, [state, productId, dispatch]);
const handleFetch = () => {
dispatch('FETCH');
};
return (
Product Details
{state === 'idle' && }
{state === 'loading' && Loading...
}
{state === 'success' && (
{productData.name}
{productData.description}
Price: ${productData.price}
)}
{state === 'error' && Error: {error}
}
);
}
export default ProductDetails;
Paaiškinimas:
- Mes apibrėžiame
productDetailsMachine
kaip paprastą JavaScript objektą, atspindintį mūsų būsenų mašiną. - Mes naudojame
React.useReducer
būsenos perėjimams valdyti pagal mūsų mašiną. - Mes naudojame React
useEffect
„hook“, kad paleistume duomenų gavimą, kai būsena yra 'loading'. handleFetch
funkcija išsiunčia 'FETCH' įvykį, pradedant krovimo būseną.- Komponentas atvaizduoja skirtingą turinį priklausomai nuo dabartinės būsenos.
useActionState
naudojimas (Hipotetinis - React 19 funkcija)
Nors useActionState
dar nėra visiškai prieinamas, štai kaip atrodytų implementacija, kai ji bus prieinama, siūlanti švaresnį požiūrį:
import React from 'react';
//import { useActionState } from 'react'; // Atkomentuokite, kai bus prieinama
const productDetailsMachine = {
initial: 'idle',
states: {
idle: {
on: {
FETCH: 'loading',
},
},
loading: {
on: {
SUCCESS: 'success',
ERROR: 'error',
},
},
success: {
type: 'final',
},
error: {
on: {
FETCH: 'loading',
},
},
},
};
function ProductDetails({ productId }) {
const initialState = { state: productDetailsMachine.initial, data: null, error: null };
// Hipotetinė useActionState implementacija
const [newState, dispatch] = React.useReducer(
(state, event) => {
const nextState = productDetailsMachine.states[state.state].on[event];
return nextState ? { ...state, state: nextState } : state; // Grąžinti kitą būseną arba dabartinę, jei perėjimas neapibrėžtas
},
initialState
);
const handleFetchProduct = async () => {
dispatch('FETCH');
try {
const response = await fetch(`https://api.example.com/products/${productId}`); // Pakeiskite savo API galiniu tašku
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
// Sėkmingai gauta - išsiųskite SUCCESS su duomenimis!
dispatch('SUCCESS');
// Išsaugokite gautus duomenis vietinėje būsenoje. Negalima naudoti dispatch reduktoriaus viduje.
newState.data = data; // Atnaujinkite ne dispečerio viduje
} catch (error) {
// Įvyko klaida - išsiųskite ERROR su klaidos pranešimu!
dispatch('ERROR');
// Išsaugokite klaidą naujame kintamajame, kad būtų rodoma render() metode
newState.error = error.message;
}
//}, initialState);
};
return (
Product Details
{newState.state === 'idle' && }
{newState.state === 'loading' && Loading...
}
{newState.state === 'success' && newState.data && (
{newState.data.name}
{newState.data.description}
Price: ${newState.data.price}
)}
{newState.state === 'error' && newState.error && Error: {newState.error}
}
);
}
export default ProductDetails;
Svarbi pastaba: Šis pavyzdys yra hipotetinis, nes useActionState
dar nėra visiškai prieinamas ir jo tikslus API gali keistis. Aš jį pakeičiau standartiniu useReducer, kad pagrindinė logika veiktų. Tačiau ketinama parodyti, kaip *jūs* jį naudotumėte, jei jis taptų prieinamas ir jūs turėtumėte pakeisti useReducer į useActionState. Ateityje su useActionState
, šis kodas turėtų veikti kaip paaiškinta su minimaliais pakeitimais, labai supaprastinant asinchroninių duomenų tvarkymą.
useActionState
naudojimo su būsenų mašinomis privalumai
- Aiškus atsakomybių atskyrimas: Būsenos logika yra inkapsuliuota būsenų mašinoje, o vartotojo sąsajos atvaizdavimą tvarko React komponentas.
- Pagerintas kodo skaitomumas: Būsenų mašina suteikia vizualų programos elgsenos vaizdą, todėl ją lengviau suprasti ir palaikyti.
- Supaprastintas asinchroninis tvarkymas:
useActionState
supaprastina asinchroninių veiksmų tvarkymą, mažinant pasikartojančio kodo kiekį. - Patobulintas testuojamumas: Būsenų mašinos yra iš prigimties testuojamos, todėl galite lengvai patikrinti savo programos elgsenos teisingumą.
Pažangios koncepcijos ir svarstymai
XState integracija
Sudėtingesniems būsenos valdymo poreikiams apsvarstykite galimybę naudoti specializuotą būsenų mašinų biblioteką, tokią kaip XState. XState suteikia galingą ir lanksčią sistemą būsenų mašinoms apibrėžti ir valdyti, su tokiomis funkcijomis kaip hierarchinės būsenos, lygiagrečios būsenos, apsaugos (guards) ir veiksmai (actions).
// Pavyzdys naudojant XState
import { createMachine, useMachine } from 'xstate';
const productDetailsMachine = createMachine({
id: 'productDetails',
initial: 'idle',
states: {
idle: {
on: {
FETCH: 'loading',
},
},
loading: {
invoke: {
id: 'fetchProduct',
src: (context, event) => fetch(`https://api.example.com/products/${context.productId}`).then(res => res.json()),
onDone: {
target: 'success',
actions: assign({ product: (context, event) => event.data })
},
onError: {
target: 'error',
actions: assign({ error: (context, event) => event.data })
}
}
},
success: {
type: 'final',
},
error: {
on: {
FETCH: 'loading',
},
},
},
}, {
services: {
fetchProduct: (context, event) => fetch(`https://api.example.com/products/${context.productId}`).then(res => res.json())
}
});
Tai suteikia deklaratyvesnį ir patikimesnį būdą valdyti būseną. Būtinai įdiekite ją naudodami: npm install xstate
Globalus būsenos valdymas
Programoms su sudėtingais būsenos valdymo reikalavimais keliuose komponentuose, apsvarstykite galimybę naudoti globalų būsenos valdymo sprendimą, tokį kaip Redux ar Zustand, kartu su būsenų mašinomis. Tai leidžia centralizuoti jūsų programos būseną ir lengvai ja dalintis tarp komponentų.
Būsenų mašinų testavimas
Būsenų mašinų testavimas yra labai svarbus siekiant užtikrinti jūsų programos teisingumą ir patikimumą. Galite naudoti testavimo sistemas, tokias kaip Jest ar Mocha, rašyti vienetų testus savo būsenų mašinoms, tikrinant, ar jos pereina tarp būsenų kaip tikėtasi ir teisingai tvarko skirtingus įvykius.
Štai paprastas pavyzdys:
// Pavyzdinis Jest testas
import { interpret } from 'xstate';
import { productDetailsMachine } from './productDetailsMachine';
describe('productDetailsMachine', () => {
it('should transition from idle to loading on FETCH event', (done) => {
const service = interpret(productDetailsMachine).onTransition((state) => {
if (state.value === 'loading') {
expect(state.value).toBe('loading');
done();
}
});
service.start();
service.send('FETCH');
});
});
Internacionalizacija (i18n)
Kuriant programas pasaulinei auditorijai, internacionalizacija (i18n) yra būtina. Užtikrinkite, kad jūsų būsenų mašinos logika ir vartotojo sąsajos atvaizdavimas būtų tinkamai internacionalizuoti, kad palaikytų kelias kalbas ir kultūrinius kontekstus. Apsvarstykite šiuos dalykus:
- Teksto turinys: Naudokite i18n bibliotekas, kad išverstumėte teksto turinį pagal vartotojo lokalę.
- Datos ir laiko formatai: Naudokite lokalę palaikančias datos ir laiko formatavimo bibliotekas, kad datos ir laikai būtų rodomi teisingu formatu pagal vartotojo regioną.
- Valiutos formatai: Naudokite lokalę palaikančias valiutos formatavimo bibliotekas, kad valiutos vertės būtų rodomos teisingu formatu pagal vartotojo regioną.
- Skaičių formatai: Naudokite lokalę palaikančias skaičių formatavimo bibliotekas, kad skaičiai būtų rodomi teisingu formatu pagal vartotojo regioną (pvz., dešimtainiai skyrikliai, tūkstančių skyrikliai).
- Iš dešinės į kairę (RTL) išdėstymas: Palaikykite RTL išdėstymus kalboms, tokioms kaip arabų ir hebrajų.
Atsižvelgdami į šiuos i18n aspektus, galite užtikrinti, kad jūsų programa bus prieinama ir patogi naudoti pasaulinei auditorijai.
Išvada
React useActionState
derinimas su būsenų mašinomis siūlo galingą požiūrį kuriant patikimas ir nuspėjamas vartotojo sąsajas. Atskyrus būsenos logiką nuo vartotojo sąsajos atvaizdavimo ir užtikrinant aiškų kontrolės srautą, būsenų mašinos pagerina kodo organizavimą, palaikomumą ir testuojamumą. Nors useActionState
vis dar yra būsima funkcija, supratimas, kaip integruoti būsenų mašinas dabar, paruoš jus pasinaudoti jos privalumais, kai ji taps prieinama. Bibliotekos, tokios kaip XState, suteikia dar pažangesnes būsenos valdymo galimybes, palengvinančias sudėtingos programos logikos tvarkymą.
Prisijaukinę būsenų mašinas ir useActionState
, galite pakelti savo React kūrimo įgūdžius ir kurti patikimesnes, lengviau palaikomas ir patogesnes vartotojams visame pasaulyje programas.