Atklājiet stāvokļa mašīnu jaudu React ar pielāgotajiem āķiem. Iemācieties abstrahēt sarežģītu loģiku, uzlabot koda uzturamību un veidot stabilas lietojumprogrammas.
React pielāgotais āķis stāvokļa mašīna: Sarežģītas stāvokļa loģikas abstrakcijas apguve
React lietojumprogrammām kļūstot sarežģītākām, stāvokļa pārvaldība var kļūt par būtisku izaicinājumu. Tradicionālās pieejas, izmantojot `useState` un `useEffect`, var ātri novest pie sapītas loģikas un grūti uzturama koda, īpaši, ja tiek apstrādātas sarežģītas stāvokļa pārejas un blakusefekti. Šeit palīgā nāk stāvokļa mašīnas, un jo īpaši React pielāgotie āķi, kas tās ievieš. Šis raksts iepazīstinās jūs ar stāvokļa mašīnu koncepciju, parādīs, kā tās ieviest kā pielāgotos āķus React, un ilustrēs to sniegtos ieguvumus mērogojamu un uzturamu lietojumprogrammu veidošanai globālai auditorijai.
Kas ir stāvokļa mašīna?
Stāvokļa mašīna (vai galīgā stāvokļa mašīna, GPM) ir matemātisks aprēķinu modelis, kas apraksta sistēmas uzvedību, definējot ierobežotu stāvokļu skaitu un pārejas starp šiem stāvokļiem. Iedomājieties to kā blokshēmu, taču ar stingrākiem noteikumiem un formālāku definīciju. Galvenie jēdzieni ietver:
- Stāvokļi: Apzīmē dažādus sistēmas apstākļus vai fāzes.
- Pārejas: Definē, kā sistēma pāriet no viena stāvokļa uz citu, pamatojoties uz specifiskiem notikumiem vai apstākļiem.
- Notikumi: Aktivizētāji, kas izraisa stāvokļa pārejas.
- Sākotnējais stāvoklis: Stāvoklis, kurā sistēma sāk darboties.
Stāvokļa mašīnas izceļas ar sistēmu modelēšanu ar labi definētiem stāvokļiem un skaidrām pārejām. Reālās pasaules scenārijos ir daudz piemēru:
- Luksofori: Ciklē pa stāvokļiem, piemēram, Sarkans, Dzeltens, Zaļš, ar pārejām, ko iedarbina taimeri. Šis ir vispārīgi atpazīstams piemērs.
- Pasūtījumu apstrāde: E-komercijas pasūtījums var pāriet caur stāvokļiem, piemēram, "Gaida", "Apstrādā", "Nosūtīts" un "Piegādāts". Tas ir universāli piemērojams tiešsaistes mazumtirdzniecībā.
- Autentifikācijas plūsma: Lietotāja autentifikācijas process var ietvert stāvokļus, piemēram, "Izrakstījies", "Piesakās", "Pieslēdzies" un "Kļūda". Drošības protokoli parasti ir konsekventi dažādās valstīs.
Kāpēc izmantot stāvokļa mašīnas React?
Stāvokļa mašīnu integrēšana jūsu React komponentos piedāvā vairākas pārliecinošas priekšrocības:
- Uzlabota koda organizācija: Stāvokļa mašīnas nodrošina strukturētu pieeju stāvokļa pārvaldībai, padarot jūsu kodu paredzamāku un vieglāk saprotamu. Vairs nekāda spageti koda!
- Samazināta sarežģītība: Skaidri definējot stāvokļus un pārejas, varat vienkāršot sarežģītu loģiku un izvairīties no nevēlamiem blakusefektiem.
- Uzlabota testējamība: Stāvokļa mašīnas ir pēc savas būtības testējamas. Jūs varat viegli pārbaudīt, vai jūsu sistēma darbojas pareizi, testējot katru stāvokli un pāreju.
- Palielināta uzturamība: Stāvokļa mašīnu deklaratīvā daba atvieglo koda modificēšanu un paplašināšanu, jūsu lietojumprogrammai attīstoties.
- Labākas vizualizācijas: Pastāv rīki, kas var vizualizēt stāvokļa mašīnas, nodrošinot skaidru pārskatu par jūsu sistēmas uzvedību, palīdzot sadarbībā un izpratnē starp komandām ar dažādām prasmēm.
Stāvokļa mašīnas ieviešana kā React pielāgotais āķis
Ilustrēsim, kā ieviest stāvokļa mašīnu, izmantojot React pielāgoto āķi. Mēs izveidosim vienkāršu piemēru ar pogu, kas var būt trīs stāvokļos: `idle` (dīkstāvē), `loading` (ielādē) un `success` (veiksmīga). Poga sākas `idle` stāvoklī. Kad uz tās noklikšķina, tā pāriet uz `loading` stāvokli, simulē ielādes procesu (izmantojot `setTimeout`), un pēc tam pāriet uz `success` stāvokli.
1. Definējiet stāvokļa mašīnu
Vispirms mēs definējam mūsu pogas stāvokļa mašīnas stāvokļus un pārejas:
const buttonStateMachineDefinition = {
initial: 'idle',
states: {
idle: {
on: {
CLICK: 'loading',
},
},
loading: {
after: {
2000: 'success', // Pēc 2 sekundēm pāreja uz success
},
},
success: {},
},
};
Šī konfigurācija izmanto bibliotēkas neatkarīgu (lai gan iedvesmojoties no XState) pieeju stāvokļa mašīnas definēšanai. Mēs paši ieviesīsim loģiku, lai interpretētu šo definīciju pielāgotajā āķī. Rekvizīts `initial` iestata sākotnējo stāvokli uz `idle`. Rekvizīts `states` definē iespējamos stāvokļus (`idle`, `loading` un `success`) un to pārejas. Stāvoklim `idle` ir rekvizīts `on`, kas definē pāreju uz `loading` stāvokli, kad notiek `CLICK` notikums. Stāvoklis `loading` izmanto rekvizītu `after`, lai automātiski pārietu uz `success` stāvokli pēc 2000 milisekundēm (2 sekundēm). Stāvoklis `success` šajā piemērā ir gala stāvoklis.
2. Izveidojiet pielāgoto āķi
Tagad izveidosim pielāgoto āķi, kas ievieš stāvokļa mašīnas loģiku:
import { useState, useEffect } from 'react';
const useStateMachine = (stateMachineDefinition) => {
const [currentState, setCurrentState] = useState(stateMachineDefinition.initial);
const [context, setContext] = useState({});
const transition = (event) => {
const stateDefinition = stateMachineDefinition.states[currentState];
if (stateDefinition && stateDefinition.on && stateDefinition.on[event]) {
setCurrentState(stateDefinition.on[event]);
}
};
useEffect(() => {
const stateDefinition = stateMachineDefinition.states[currentState];
if (stateDefinition && stateDefinition.after) {
const timeoutKeys = Object.keys(stateDefinition.after);
timeoutKeys.forEach(timeoutKey => {
const timeout = parseInt(timeoutKey, 10);
const nextState = stateDefinition.after[timeoutKey];
const timer = setTimeout(() => {
setCurrentState(nextState);
clearTimeout(timer);
}, timeout);
return () => clearTimeout(timer); // Tīrīšana atvienošanas vai stāvokļa maiņas gadījumā
});
}
}, [currentState, stateMachineDefinition.states]);
return {
currentState,
context,
transition,
};
};
export default useStateMachine;
Šis `useStateMachine` āķis kā argumentu pieņem stāvokļa mašīnas definīciju. Tas izmanto `useState`, lai pārvaldītu pašreizējo stāvokli un kontekstu (kontekstu paskaidrosim vēlāk). Funkcija `transition` kā argumentu pieņem notikumu un atjaunina pašreizējo stāvokli, pamatojoties uz definētajām pārejām stāvokļa mašīnas definīcijā. `useEffect` āķis apstrādā rekvizītu `after`, iestatot taimerus, lai automātiski pārietu uz nākamo stāvokli pēc noteikta ilguma. Āķis atgriež pašreizējo stāvokli, kontekstu un funkciju `transition`.
3. Izmantojiet pielāgoto āķi komponentē
Visbeidzot, izmantosim pielāgoto āķi React komponentē:
import React from 'react';
import useStateMachine from './useStateMachine';
const buttonStateMachineDefinition = {
initial: 'idle',
states: {
idle: {
on: {
CLICK: 'loading',
},
},
loading: {
after: {
2000: 'success', // Pēc 2 sekundēm pāreja uz success
},
},
success: {},
},
};
const MyButton = () => {
const { currentState, transition } = useStateMachine(buttonStateMachineDefinition);
const handleClick = () => {
if (currentState === 'idle') {
transition('CLICK');
}
};
let buttonText = 'Click Me';
if (currentState === 'loading') {
buttonText = 'Loading...';
} else if (currentState === 'success') {
buttonText = 'Success!';
}
return (
);
};
export default MyButton;
Šis komponents izmanto `useStateMachine` āķi, lai pārvaldītu pogas stāvokli. Funkcija `handleClick` izsūta `CLICK` notikumu, kad tiek noklikšķināts uz pogas (un tikai tad, ja tā ir `idle` stāvoklī). Komponents renderē atšķirīgu tekstu, pamatojoties uz pašreizējo stāvokli. Poga ir atspējota ielādes laikā, lai novērstu vairākkārtējus klikšķus.
Konteksta apstrāde stāvokļa mašīnās
Daudzos reālās pasaules scenārijos stāvokļa mašīnām ir jāpārvalda dati, kas saglabājas pāri stāvokļa pārejām. Šos datus sauc par kontekstu. Konteksts ļauj jums glabāt un atjaunināt attiecīgo informāciju, stāvokļa mašīnai virzoties uz priekšu.
Paplašināsim mūsu pogas piemēru, iekļaujot skaitītāju, kas tiek palielināts katru reizi, kad poga veiksmīgi ielādējas. Mēs modificēsim stāvokļa mašīnas definīciju un pielāgoto āķi, lai apstrādātu kontekstu.
1. Atjauniniet stāvokļa mašīnas definīciju
const buttonStateMachineDefinition = {
initial: 'idle',
context: {
count: 0,
},
states: {
idle: {
on: {
CLICK: 'loading',
},
},
loading: {
after: {
2000: 'success',
},
},
success: {
entry: (context) => {
return { ...context, count: context.count + 1 };
},
},
},
};
Mēs esam pievienojuši `context` rekvizītu stāvokļa mašīnas definīcijai ar sākotnējo `count` vērtību 0. Mēs esam arī pievienojuši `entry` darbību `success` stāvoklim. `entry` darbība tiek izpildīta, kad stāvokļa mašīna ieiet `success` stāvoklī. Tā kā argumentu pieņem pašreizējo kontekstu un atgriež jaunu kontekstu ar palielinātu `count` vērtību. `entry` šeit parāda piemēru konteksta modificēšanai. Tā kā Javascript objekti tiek nodoti pēc atsauces, ir svarīgi atgriezt *jaunu* objektu, nevis mutēt oriģinālu.
2. Atjauniniet pielāgoto āķi
import { useState, useEffect } from 'react';
const useStateMachine = (stateMachineDefinition) => {
const [currentState, setCurrentState] = useState(stateMachineDefinition.initial);
const [context, setContext] = useState(stateMachineDefinition.context || {});
const transition = (event) => {
const stateDefinition = stateMachineDefinition.states[currentState];
if (stateDefinition && stateDefinition.on && stateDefinition.on[event]) {
setCurrentState(stateDefinition.on[event]);
}
};
useEffect(() => {
const stateDefinition = stateMachineDefinition.states[currentState];
if(stateDefinition && stateDefinition.entry){
const newContext = stateDefinition.entry(context);
setContext(newContext);
}
if (stateDefinition && stateDefinition.after) {
const timeoutKeys = Object.keys(stateDefinition.after);
timeoutKeys.forEach(timeoutKey => {
const timeout = parseInt(timeoutKey, 10);
const nextState = stateDefinition.after[timeoutKey];
const timer = setTimeout(() => {
setCurrentState(nextState);
clearTimeout(timer);
}, timeout);
return () => clearTimeout(timer); // Tīrīšana atvienošanas vai stāvokļa maiņas gadījumā
});
}
}, [currentState, stateMachineDefinition.states, context]);
return {
currentState,
context,
transition,
};
};
export default useStateMachine;
Mēs esam atjauninājuši `useStateMachine` āķi, lai inicializētu `context` stāvokli ar `stateMachineDefinition.context` vai tukšu objektu, ja konteksts nav nodrošināts. Mēs esam arī pievienojuši `useEffect`, lai apstrādātu `entry` darbību. Kad pašreizējam stāvoklim ir `entry` darbība, mēs to izpildām un atjauninām kontekstu ar atgriezto vērtību.
3. Izmantojiet atjaunināto āķi komponentē
import React from 'react';
import useStateMachine from './useStateMachine';
const buttonStateMachineDefinition = {
initial: 'idle',
context: {
count: 0,
},
states: {
idle: {
on: {
CLICK: 'loading',
},
},
loading: {
after: {
2000: 'success',
},
},
success: {
entry: (context) => {
return { ...context, count: context.count + 1 };
},
},
},
};
const MyButton = () => {
const { currentState, context, transition } = useStateMachine(buttonStateMachineDefinition);
const handleClick = () => {
if (currentState === 'idle') {
transition('CLICK');
}
};
let buttonText = 'Click Me';
if (currentState === 'loading') {
buttonText = 'Loading...';
} else if (currentState === 'success') {
buttonText = 'Success!';
}
return (
Count: {context.count}
);
};
export default MyButton;
Tagad mēs piekļūstam `context.count` komponentē un parādām to. Katru reizi, kad poga veiksmīgi ielādējas, skaitītājs palielināsies.
Uzlabotas stāvokļa mašīnu koncepcijas
Lai gan mūsu piemērs ir relatīvi vienkāršs, stāvokļa mašīnas var apstrādāt daudz sarežģītākus scenārijus. Šeit ir daži uzlaboti jēdzieni, kas jāņem vērā:
- Aizsargi (Guards): Nosacījumi, kas jāizpilda, lai notiktu pāreja. Piemēram, pāreja var būt atļauta tikai tad, ja lietotājs ir autentificēts vai ja noteikta datu vērtība pārsniedz slieksni.
- Darbības (Actions): Blakusefekti, kas tiek izpildīti, ieejot vai izejot no stāvokļa. Tie var ietvert API izsaukumus, DOM atjaunināšanu vai notikumu nosūtīšanu citiem komponentiem.
- Paralēlie stāvokļi: Ļauj modelēt sistēmas ar vairākām vienlaicīgām darbībām. Piemēram, video atskaņotājam var būt viena stāvokļa mašīna atskaņošanas vadīšanai (atskaņot, apturēt, pārtraukt) un cita video kvalitātes pārvaldībai (zema, vidēja, augsta).
- Hierarhiskie stāvokļi: Ļauj ligzdot stāvokļus citos stāvokļos, veidojot stāvokļu hierarhiju. Tas var būt noderīgi sarežģītu sistēmu modelēšanai ar daudziem saistītiem stāvokļiem.
Alternatīvās bibliotēkas: XState un citas
Lai gan mūsu pielāgotais āķis nodrošina stāvokļa mašīnas pamata ieviešanu, vairākas izcilas bibliotēkas var vienkāršot procesu un piedāvāt uzlabotas funkcijas.
XState
XState ir populāra JavaScript bibliotēka stāvokļa mašīnu un stāvokļa diagrammu izveidei, interpretēšanai un izpildei. Tā nodrošina jaudīgu un elastīgu API sarežģītu stāvokļa mašīnu definēšanai, ieskaitot atbalstu aizsargiem (guards), darbībām (actions), paralēliem stāvokļiem un hierarhiskiem stāvokļiem. XState piedāvā arī izcilus rīkus stāvokļa mašīnu vizualizēšanai un atkļūdošanai.
Citas bibliotēkas
Citas iespējas ietver:
- Robot: Viegla stāvokļa pārvaldības bibliotēka, kas koncentrējas uz vienkāršību un veiktspēju.
- react-automata: Bibliotēka, kas īpaši paredzēta stāvokļa mašīnu integrēšanai React komponentos.
Bibliotēkas izvēle ir atkarīga no jūsu projekta specifiskajām vajadzībām. XState ir laba izvēle sarežģītām stāvokļa mašīnām, savukārt Robot un react-automata ir piemēroti vienkāršākiem scenārijiem.
Labākā prakse stāvokļa mašīnu izmantošanai
Lai efektīvi izmantotu stāvokļa mašīnas jūsu React lietojumprogrammās, ņemiet vērā šādus labākās prakses principus:
- Sāciet ar mazumiņu: Sāciet ar vienkāršām stāvokļa mašīnām un pakāpeniski palieliniet sarežģītību pēc vajadzības.
- Vizualizējiet savu stāvokļa mašīnu: Izmantojiet vizualizācijas rīkus, lai iegūtu skaidru izpratni par savas stāvokļa mašīnas uzvedību.
- Rakstiet visaptverošus testus: Rūpīgi pārbaudiet katru stāvokli un pāreju, lai nodrošinātu, ka jūsu sistēma darbojas pareizi.
- Dokumentējiet savu stāvokļa mašīnu: Skaidri dokumentējiet savas stāvokļa mašīnas stāvokļus, pārejas, aizsargus un darbības.
- Apsveriet internacionalizāciju (i18n): Ja jūsu lietojumprogramma ir paredzēta globālai auditorijai, nodrošiniet, lai jūsu stāvokļa mašīnas loģika un lietotāja saskarne būtu pareizi internacionalizēta. Piemēram, izmantojiet atsevišķas stāvokļa mašīnas vai kontekstu, lai apstrādātu dažādus datumu formātus vai valūtas simbolus, pamatojoties uz lietotāja lokāli.
- Pieejamība (a11y): Nodrošiniet, lai jūsu stāvokļa pārejas un UI atjauninājumi būtu pieejami lietotājiem ar invaliditāti. Izmantojiet ARIA atribūtus un semantisko HTML, lai nodrošinātu atbilstošu kontekstu un atgriezenisko saiti palīgtehnoloģijām.
Secinājums
React pielāgotie āķi apvienojumā ar stāvokļa mašīnām nodrošina jaudīgu un efektīvu pieeju sarežģītas stāvokļa loģikas pārvaldībai React lietojumprogrammās. Abstrahējot stāvokļa pārejas un blakusefektus labi definētā modelī, jūs varat uzlabot koda organizāciju, samazināt sarežģītību, uzlabot testējamību un palielināt uzturamību. Neatkarīgi no tā, vai jūs ieviešat savu pielāgoto āķi vai izmantojat tādu bibliotēku kā XState, stāvokļa mašīnu iekļaušana jūsu React darbplūsmā var ievērojami uzlabot jūsu lietojumprogrammu kvalitāti un mērogojamību lietotājiem visā pasaulē.