Articles

Állapotgépek összehasonlítása:

Az állapotkezelés a Reactban nehézkessé válhat, ahogy az alkalmazás logikája egyre összetettebbé válik. Az olyan harmadik féltől származó könyvtárak, mint a Redux, a Flux és a MobX segítenek, de még ezeknek az eszközöknek is megvan a maguk terhe.

Az állapotgép, más néven véges állapotgép vagy véges állapotú automata a számítás matematikai modellje. Ez egy absztrakt gép, amelynek egy adott időpontban véges számú állapota van.

Ezzel az útmutatóval áttekintjük két állapotgép – az XState és a Robot – hasonlóságait, különbségeit, előnyeit és hátrányait, és végigvesszük, hogyan használhatjuk őket a React alkalmazások állapotkezelésének egyszerűsítésére.

Miért használjunk állapotgépet?

Az állapot a legtöbb frontend alkalmazás fontos része, különösen a Reactban. Gondoljunk az állapotra úgy, mint az alkalmazás azon részének reprezentációjára, amelyik változik.

Gondoljunk egy olyan komponensre, amelyik adatokat hív le egy API-ból.

const Todo = () => { const = useState(); const handleClick = () => { fetch('https://jsonplaceholder.typicode.com/todos/1') .then(response => response.json()) .then(todo => setData(data.push(todo)) .catch(error => console.error(error) ) } return( <div> <button onClick={handleClick}> Fetch Data </button> {data && data.map(todo => (<p key={todo.id}> {todo.title} <span> {todo.completed} </span></p>) )} </div> ); }

Ebben a példában az adatok a mi állapotunk, mivel ez az alkalmazás azon része, amelyik változik, amikor egy esemény bekövetkezik – ebben az esetben egy gomb kattintása. A probléma ezzel a beállítással az, hogy bonyolulttá válhat.

Mi történik, amíg a felhasználó a rekord lekérdezésére vár, vagy ha a lekérdezés közben hiba lép fel? Több állapotot kell hozzáadnunk, hogy ezeket a problémákat kezelni tudjuk.

const Todo = () => { const = useState(false); const = useState(); const = useState(false); const handleClick = () => { setLoading(true); fetch('https://jsonplaceholder.typicode.com/todos/1') .then(response => response.json()) .then(todo => { setLoading(false); setData(data.push(todo)); }) .catch(error => { setLoading(false); setIsError(true); }) } return( <div> {loading && <p> Loading Data... </p>} <button onClick={handleClick}> Fetch Data </button> {data && data.map(todo => (<p key={todo.id}> {todo.title} <span> {todo.completed} </span></p>) )} {error && <p> An error occured. Try again.</p>} </div> ); } 

Ha az alkalmazásunk összetett, a dolgok gyorsan kicsúszhatnak a kezünkből, ahogy új funkciókat adunk hozzá, ami megnehezíti a kód megértését, tesztelését és továbbfejlesztését.

Az állapotgépek másképp közelítik meg ezt az egyedi problémát. Az állapotgépekkel meghatározhatjuk az összes állapotot, amelyben az alkalmazásunk lehet, az állapotok közötti átmeneteket és a fellépő mellékhatásokat. Ez segít elkerülni azt a helyzetet, amikor az alkalmazás egy lehetetlen állapotban van.

State Diagram

State Diagram

Az alkalmazásunk a következő állapotokban lehet:

  1. ready – a kezdeti állapot, amikor az alkalmazás elindul
  2. loading – amikor egy esemény bekövetkezik i.Pl. egy gomb megnyomása
  3. success – amikor a betöltés megoldódik
  4. error – amikor a betöltés elutasításra kerül

Az alkalmazás egyik állapotból a másikba akkor lép át, amikor egy művelet kiváltásra kerül – ill, amikor a felhasználó rákattint egy gombra. Jobban irányíthatod az alkalmazásodat, ha előre látod az összes lehetséges állapotot, amiben lehet.

Mit csinál az XState és a Robot?

A hivatalos dokumentációja szerint az XState egy könyvtár véges állapotgépek és állapotábrák létrehozására, értelmezésére és végrehajtására, valamint ezen gépek meghívásainak aktorként való kezelésére. David Khourshid hozta létre a felhasználói felületek állapotproblémáinak megoldására.

A Robot egy könnyű, funkcionális és megváltoztathatatlan könyvtár, amelyet Mathew Philips hozott létre véges állapotgépek létrehozására. Az XState, a Statecharts és a P programozási nyelv inspirálta.

Előfeltételek

A bemutató követéséhez szükséged lesz:

  • Javascript ismeret
  • React ismeret
  • yarn vagy npm v5.2 vagy nagyobb
  • Node 10-es vagy nagyobb verzió

Kezdés

Az XState és a Robot közötti hasonlóságok és különbségek bemutatásához létrehozunk egy alkalmazást, amely adatokat hív le egy API-ból.

Nyissunk meg egy terminált, és inicializáljunk egy React alkalmazást.

npx create-react-app state-machine

Ezzel létrehozunk egy State Machine nevű React alkalmazást.

Ezután hozzunk létre egy szolgáltatást az adatok API-ból való lehívásához.

cd src && touch fetchTodo.js

A fenti parancs létrehoz egy fetchTodo.js nevű fájlt a src könyvtárban.

Nyissuk meg a fájlt, és adjuk meg a következőket.

export const fetchTodo = () => { return fetch('https://jsonplaceholder.typicode.com/todos/1') .then((response) => response.json()) .then((todo) => todo);};

Lényegében bármikor, amikor a fetchTodo függvényt meghívjuk, az API-ból lekért adatokat adja vissza.

Telepítés

Az XState telepíthető az npm vagy a yarn használatával, vagy a szkript beágyazásával egy CDN-en keresztül.

A könyvtár npm segítségével történő telepítéséhez nyissunk terminált és futtassuk:

npm install xstate @xstate/react

Ez telepíti a xstate core könyvtárat és egy @xstate/react nevű csomagot a React számára, amely lehetővé teszi az egyéni XState horgok használatát a React alkalmazásokban.

A Robotot az npm vagy a yarn segítségével telepítheti, de CDN-t nem használhat.

A Robot telepítéséhez indítson el egy terminált, és futtassa a következő parancsot.

npm install robot3 react-robot

A Robot egy csomagot is kínál az egyéni horgok Reactben való használatához react-robot

Gép létrehozása

Az állapotgép használata előtt először definiálnunk kell azt.

A src könyvtárban hozzunk létre egy xstateMachine.js nevű fájlt. Másoljuk az alábbi kódot a létrehozott fájlba.

import { Machine, assign } from 'xstate';import { fetchTodo } from '../fetchTodo';export const xstateMachine = Machine({ id: 'clickButton', initial: 'ready', context: { todo: null, }, states: { ready: { on: { CLICK: 'loading', }, }, loading: { invoke: { id: 'fetch-todo', src: fetchTodo, onDone: { target: 'success', actions: assign({ todo: (context, event) => event.data, }), }, onError: 'error', }, }, success: { on: { CLICK: 'loading', }, }, error: { on: { CLICK: 'loading', }, }, },});

A gépeket a Machine() gyári függvény segítségével definiáljuk. A fenti kódban definiált gép ID-kből, állapotokból, kontextusokból, akciókból és átmenetekből áll. Az ID-k az állapotcsomópontok azonosítására szolgálnak.

A gép állapotai a következők:

  • ready
  • loading
  • success
  • error

A kontextus egy kiterjesztett állapot, amelyet mennyiségi adatok, például számok, tetszőleges string, objektumok stb. megjelenítésére használunk. Az alkalmazás kezdeti állapota readyként van definiálva. Amikor egy gombra kattintunk, egy átmenet történik, amely az állapotot a ready állapotból a loading állapotba helyezi át.

A loading állapotban van egy invoke tulajdonság, amely egy ígéret feloldásáért vagy elutasításáért felelős. Amikor a fetchTodo ígéret feloldásra kerül, a loading állapot átmegy a success állapotba, és a assign művelet frissíti a kontextust az ígéretből kapott eredménnyel. Visszautasítás esetén a error állapotba lép.

A Robot segítségével egy gép létrehozása hasonló, bár néhány lényeges különbséggel. Az egyik fő különbség az, hogy mivel a Robot egy funkcionális könyvtár, a legtöbb műveletet függvények segítségével hajtjuk végre, ellentétben az XState-tel, amely opciós objektumokat használ.

Készítsünk egy robotMachine.js nevű fájlt a src könyvtárunkban, és illesszük be a következőket.

 import { createMachine, invoke, reduce, state, transition } from 'robot3';import { fetchTodo } from '../fetchTodo';const context = () => ({ todo: {},});export const robotMachine = createMachine( { ready: state(transition('CLICK', 'loading')), loading: invoke( fetchTodo, transition( 'done', 'success', reduce((ctx, evt) => ({ ...ctx, todo: evt.data })) ), transition( 'error', 'error', reduce((ctx, ev) => ({ ...ctx, error: ev.error })) ) ), success: state(transition('CLICK', 'loading')), error: state(transition('CLICK', 'loading')), }, context);

A Robotban a gépek létrehozása a createMachine függvény segítségével történik, amely egy objektumot fogad el. Egy állapotot a state függvénnyel definiálunk, és paraméterként elfogadhat egy transition függvényt.

Az egyik állapotból a másikba való átlépés a transition függvénnyel történik, amely paraméterként elfogadja az eseményt és a következő állapotot. Opcionálisan a transition függvényhez harmadik paraméterként hozzáadható a reduce függvény. A reduce függvények paraméterként egy reducer függvényt fogadnak el, amely a kontextus frissítésére szolgál.

A robotnak van egy invoke függvénye is, amely hasonló az XState invoke tulajdonságához. Amikor az alkalmazás loading állapotban van, a invoke függvényt hívja meg. A invoke függvény egyfajta állapot, amely egy ígéretet hív meg, és egy függvényt vagy egy másik gépet ad vissza. Ha a invoke függvény feloldja az ígéretet, akkor egy done eseményt küld. Ha elutasítja, akkor egy error eseményt küld.

A komponens megépítése

Most, hogy a gépünk készen áll, a következő lépés a gépet használó komponens megépítése.

Készítsünk egy fájlt a src könyvtárunkban a komponenshez, és illesszük be a következőket.

import React from 'react';import { useMachine } from '@xstate/react';import { xstateMachine } from './stateMachine';function Todo() { const = useMachine(xstateMachine); const { todo } = current.context; return ( <div> <button onClick={() => send('CLICK')}>Fetch Todo XState</button> {current.matches('loading') && <p>loading...</p>} {current.matches('success') && ( <p key={todo.id}> {todo.title} <span> {todo.completed} </span> </p> )} {current.matches('error') && <p>An error occured</p>} </div> );}export default Todo;

A gép használatához importálnunk kell a useMachine hook-ot a @xstate/react library-ből, valamint a korábban létrehozott gépet.

A useMachine hook egy React Hook, amely értelmezi a gépet. Felelős egy szolgáltatás elindításáért, hogy az egy komponens teljes életciklusa alatt fusson.

A useMachinehorog egy gépet fogad el paraméterként, és egy tömböt ad vissza. A tömb tartalmazza a current állapotot és a send-t, amely egy olyan függvény, amely eseményt küld a useMachine hook által létrehozott szolgáltatásnak.

A current állapot egy objektum, amely tartalmazza az állapotot, a kontextust és néhány segédfüggvényt. Az aktuális állapot ellenőrzéséhez használja a matches tulajdonságot, amely egy boolean értéket ad vissza. Amikor a felhasználó rákattint a gombra, az eseményt küld a szolgáltatásnak. Ezután az ellenőrzi a gép aktuális állapotát, és az állapot alapján megjeleníti a megfelelő felhasználói felületet.

A Robot megközelítése a komponensek építéséhez hasonló. Egy Robot segítségével épített komponens így nézne ki:

import React from 'react';import { useMachine } from 'react-robot';import { robotMachine } from './robotMachine';function Todo() { const = useMachine(robotMachine); const { todo } = current.context; return ( <div> <button onClick={() => send('CLICK')}>Fetch Todo Robot</button> {current.name === 'loading' && <p>loading...</p>} {current.name === 'success' && ( <p key={todo.id}> {todo.title} <span> {todo.completed} </span> </p> )} {current.name === 'error' && <p>An error occured</p>} </div> );}export default RobotTodo;

A Robotnak van egy useMachine kampója is, amelyet a react-robot library importálásával érhetünk el. A különbség a megvalósításban abban van, ahogyan egy állapotot összehasonlítanak. Míg az XState a matches tulajdonságot használja, ami egy függvény, amely elfogadja az összehasonlítani kívánt karakterláncot, addig a Robot a name tulajdonságot használja az aktuális állapot ellenőrzésére az összehasonlítás előtt.

Következtetés

Az állapotgépek sokkal jobban szervezett módot kínálnak az állapot kezelésére a React alkalmazásokban, és más alternatívákhoz képest könnyen skálázhatóak. Az XState és a Robot két nagyon népszerű könyvtár, amelyek bár nagyon hasonlóak, nagyon különböző nézőpontból közelítik meg az állapotgépek kezelését.

Az ehhez a bemutatóhoz tartozó tároló elérhető a GitHubon.

További információkért nézd meg a következő forrásokat.

  • Robot dokumentáció
  • XState dokumentáció
  • “Infinitely Better UIs with Finite Automata” (videó)

Teljes átláthatóság a produktív React alkalmazásokban

A React alkalmazások hibakeresése nehéz lehet, különösen, ha a felhasználók olyan problémákat tapasztalnak, amelyeket nehéz reprodukálni. Ha érdekel a Redux állapotának figyelése és nyomon követése, a JavaScript hibák automatikus felszínre hozása, valamint a lassú hálózati kérések és a komponensek betöltési idejének nyomon követése, próbáld ki a LogRocket-t. LogRocket Dashboard Free Trial Banner

A LogRocket olyan, mint egy DVR a webes alkalmazásokhoz, amely szó szerint mindent rögzít, ami a React alkalmazásodban történik. Ahelyett, hogy találgatnád, miért történnek problémák, összesíteni és jelenteni tudod, hogy milyen állapotban volt az alkalmazásod, amikor a probléma felmerült. A LogRocket figyeli az alkalmazás teljesítményét is, és olyan mérőszámokkal készít jelentést, mint az ügyfél CPU-terhelése, az ügyfél memóriahasználata és így tovább.

A LogRocket Redux middleware csomag a felhasználói munkamenetek átláthatóságának egy extra rétegét adja hozzá. A LogRocket naplózza a Redux tárolók összes műveletét és állapotát.

Modernizálja a hibakeresés módját React alkalmazásaiban – kezdje el a monitorozást ingyen.