Używanie Mobx jako menedżera stanu w natywnych aplikacjach React
Opublikowany: 2022-03-10Zarządzanie stanem jest integralną częścią tworzenia aplikacji JavaScript, zwłaszcza aplikacji React i React Native. W tym samouczku nauczymy się używać biblioteki MobX do zarządzania stanem; zrozumieć podstawowe pojęcia, niektóre przypadki użycia i zbudować prosty przykład.
Uwaga: Podstawowa znajomość Javascript i React Native będzie bardzo przydatna podczas pracy z tym samouczkiem.
Korzystanie z MobX w aplikacjach React
Stan to dane, z którymi pracuje Twój komponent — przechowuje dane, których wymaga komponent i dyktuje, co renderuje komponent. Zarządzanie stanem to proces zarządzania aktualizacją stanu i przekazywaniem go z jednego komponentu do drugiego. Monitorowanie i praca z danymi w aplikacji może być trudna, a to wymaga bibliotek zarządzania stanem. Obsługa wszystkich danych dla Twojej aplikacji może być trochę zniechęcająca, zwłaszcza gdy Twoja aplikacja rośnie w rozmiar i złożoność, budowanie własnego narzędzia do zarządzania stanem jest nie tylko czasochłonne, ale także trudne. Dlatego możesz chcieć użyć biblioteki zarządzania stanem.
Jednak ważne jest, aby wiedzieć, że stan nie jest jedynymi danymi, które renderuje komponent, komponenty mogą również renderować przekazane mu właściwości.
Opcje zarządzania stanem
Biblioteki zarządzania stanem dla aplikacji React Native obejmują; React Context API, Redux, MobX i Unstated Next.
Chociaż każdy z tych menedżerów stanu ma swoje wady i zalety, osobiście polecam MobX ze względu na jego prostotę, minimalny szablonowy kod — nie wymaga on zmiany kodu, ponieważ w swoim rdzeniu MobX jest i wygląda jak JavaScript; nie potrzebujesz zmiany architektury, aby to obsłużyć (w przeciwieństwie do Redux i w mniejszym stopniu Context).
W rzeczywistości jest to tak niewidzialna abstrakcja, że w wielu przypadkach, jeśli usuniesz cały kod MobX — dekoratory @observable , @computed , @action i obserwator , twój kod będzie działał dokładnie tak samo (choć będzie miał pewne problemy z wydajnością ) i nie ogranicza się do państwa globalnego. Oto kilka powodów, dla których warto wybrać MobX jako menedżera stanu z wyboru dla aplikacji React Native.
Chociaż ważne jest również, aby zwrócić uwagę na pewne problemy związane z używaniem MobX jako menedżera stanu, z których niektóre obejmują unikanie zasad jego implementacji, a MobX może być trudny do debugowania, zwłaszcza gdy zmieniasz stan bezpośrednio w komponencie bez użycia @actions
parametr.
Co to jest MobX?
Zgodnie z oficjalną dokumentacją, MobX to sprawdzona w boju biblioteka, która sprawia, że zarządzanie stanem jest proste i skalowalne dzięki przejrzystemu zastosowaniu funkcjonalnego programowania reaktywnego. MobX traktuje twoją aplikację jak arkusz kalkulacyjny. Logika jest taka, że wszystko, co można wyprowadzić ze stanu aplikacji, powinno być wykonywane automatycznie .
Podstawowe zasady i koncepcja MobX
MobX różni się od innych menedżerów państwowych następującymi koncepcjami.
1. Państwo
Stan to dane, które przechowuje Twoja aplikacja — to mniej więcej cała zawartość jej pamięci. Dotyczy to również twoich komponentów.
2. Pochodne
W MobX wszystko, co można wyprowadzić ze stanu bez interakcji, jest pochodną. Przykłady wyprowadzeń obejmują:
- Interfejs użytkownika,
- Dodatki zaplecza, takie jak zmiany na serwerze.
MobX ma dwa główne typy wyprowadzeń:
- Obliczone wartości
Wartości wyliczane to w większości wartości, które można wyprowadzić z bieżącego stanu za pomocą czystych funkcji. - Reakcje
Reakcje w pochodnych to efekty uboczne, które występują w wyniku zmian w stanie aplikacji. Są one podobne do wartości obliczonej, ale zamiast wytworzenia nowej wartości, reakcja wywołuje efekt uboczny w postaci takich rzeczy, jak drukowanie na konsoli, wysyłanie żądań sieciowych, przyrostowa aktualizacja drzewa komponentów React w celu załatania DOM i tak dalej.
Złota zasada podczas korzystania z MobX polega na tym, że tworząc wartość na podstawie bieżącego stanu, użyj wartości obliczonej.
3. Działania
W przeciwieństwie do pochodnych akcje to kod, który powoduje zmiany stanu aplikacji — kod, który zmienia stan. Są wszystkim, co modyfikuje państwo. Dzięki MobX możesz to wyraźnie określić w swoim kodzie, akcje to głównie zdarzenia użytkownika, takie jak dane wejściowe, wypychanie danych zaplecza, a nawet zaplanowane zdarzenia.
Aby lepiej zrozumieć akcje, spójrzmy na przykład z dokumentacji MobX.
class Ticker { @observable tick = 0 @action increment() { this.tick++ // 'this' will always be correct } } const ticker = new Ticker() setInterval(ticker.increment, 1000)
Tutaj ustawiamy @observable
z początkową wartością 0. Następnie utworzyliśmy inkrementację funkcji, która jest również akcją, która aktualizuje wartość początkową po wykonaniu tiku co sekundę.
Obserwable w MobX
Elementy obserwowalne lub wartości obserwowalne w MobX to głównie prymitywy JavaScript, zwykłe obiekty, klasy, tablice i mapy. Są one najczęściej używane przez najpierw zadeklarowanie obserwowalnego i dodanie do niego wartości, a następnie wywołanie go przez dodanie @observable, jak pokazano poniżej:
observable(value) @observable classProperty = value
Podejście do architektury sklepu w MobX
Główna architektura MobX obejmuje części i pomysły, takie jak usługi, sklep, modele przeglądania i kontenery — niektóre z nich wyjaśniono poniżej.
- Usługa
Jest to zwykle funkcja wywoływana z kontenera; mogą służyć do pobierania danych z interfejsów API i dodawania do sklepu. - Sklep
Jak sama nazwa wskazuje, jest to centralne miejsce państwa, z którego korzysta aplikacja. Zwykle w MobX obejmują one obserwowalne, zmienne, akcje i obliczone właściwości. - Pojemnik
To wywołujeservice
i umieszcza dane z View Model do View Component jako@observer
decorator ).
MobX w aplikacjach React i natywnych
W celach edukacyjnych w tym samouczku zbudujemy prostą aplikację do tworzenia list, która umożliwi użytkownikowi dodawanie, przeglądanie i usuwanie elementów listy. Będziemy używać MobX jako menedżera stanu w tej aplikacji, aby dodawać listy, aktualizować i usuwać je ze stanu aplikacji. Jednak ważne jest, aby pamiętać, że znasz już podstawowe pojęcia JavaScript i React.
Bez zbędnych ceregieli zacznijmy!
Konfigurowanie środowiska
Teraz, gdy wiemy, czym jest i jak działa MobX, pozwól, że przeprowadzę Cię przez proces konfiguracji Twojego projektu.
Najpierw utwórzmy projekt z następującymi elementami, napisz następujący kod na swoim terminalu, aby zainicjować projekt:
npx create-react-app listapp
Powyższy kod utworzy samą aplikację React przy użyciu pakietu create-react-app. Przejdź do katalogu projektu:
cd listapp
Do tej aplikacji będziemy potrzebować trzech komponentów:
-
TitleInput
Będzie on zawierał tytuł naszego projektu i formularz wejściowy do dodawania list. -
List
Będzie to formularz wejściowy, który umożliwi użytkownikowi dodanie listy. Będzie miał przycisk dodawania, aby dodać nasze pozycje na liście. -
ListsDisplay
Ten składnik wyświetli wszystkie elementy listy użytkowników, a także przycisk usuwania, który jest generowany automatycznie, gdy użytkownik doda element listy.
Użyjemy Store.js do przechowywania stanu aplikacji i metod jej modyfikacji, podobnie jak w przypadku Redux. Opiszmy, do czego będą używane.
-
mobx
To jest menedżer stanu, którego będziemy używać w tym projekcie. -
mobx-react
To są oficjalne wiązania React dla MobX. -
bootstrap
Będziemy używać wersji bootstrap 4.5 do stylizacji naszego projektu. -
uuid
Służy do automatycznego tworzenia kluczy do usuwania list.
Zrobiwszy to, zainstalujmy te pakiety. Zamontuję je z alternatywą npm wykonaną w przędzy:
yarn add mobx mobx-react [email protected] uuid
Po zainstalowaniu pakietów uruchomimy naszą aplikację w trybie deweloperskim, uruchamiając poniższy kod w naszym terminalu:
yarn start
Konfiguracja naszego sklepu z aplikacjami
Stwórzmy sklep dla naszego projektu. Najpierw utwórz plik w katalogu głównym naszego projektu o nazwie ListStore , będzie to centralna lokalizacja stanu naszej aplikacji.
W przypadku tej aplikacji będziemy musieli utworzyć ListStore , aby nie powtarzać się, gdy używamy go w innych komponentach aplikacji.
/*** src/Store.js ***/ import { observable, action, computed } from "mobx"; import { v4 } from "uuid"; export class List { @observable value @observable done constructor (value) { this.id = v4() this.value = value } } export class ListStore { @observable lists = [] @observable filter = "" @action addList = (value) => { this.lists.push(new List(value)) } @action deleteList = (list) => { this.lists = this.lists.filter(t => t !== list) } @computed get filteredLists () { const matchCase = new RegExp(this.filter, "i") return this.lists.filter(list=> !this.filter || matchCase.test(list.value)) } }
W powyższym kodzie zaimportowaliśmy trzy funkcje z mobx
.
-
observable
Zawiera zmienną, która może być aktualizowana w przypadku zmiany stanu. -
action
Służy do modyfikowania stanu aplikacji. -
computed
Wartości, które można wyprowadzić z istniejącego stanu lub innych wartości obliczonych, zmienia się po zmodyfikowaniu stanu.
Klasa List
ma dwie wartości obiektów, które są done
, oraz value
, która będzie przechowywać stan początkowy aplikacji i modyfikację w przypadku zmian.
Chcemy, aby nasza nowa lista automatycznie tworzyła klucz, abyśmy mogli automatycznie uzyskać przycisk usuwania po utworzeniu listy. Tutaj uuid służy do automatycznego tworzenia kluczy w naszej aplikacji.
Następnie dodaliśmy funkcję addList
, która doda listy po kliknięciu za pomocą metody .push()
w celu wypchnięcia listy do tablicy, którą już utworzyliśmy w tablicy @observable lists
.
Funkcja deleteList
akceptuje List
jako właściwość, która ma być elementem, który użytkownik chce usunąć. Następnie ustawiamy wartość this.Lists
na nową tablicę po usunięciu wybranego elementu.
Zarówno addLists
, jak i deleteList
są akcjami, ponieważ modyfikują stan naszej aplikacji po wprowadzeniu zmian.
Inicjalizacja sklepu MobX
Kolejnym na naszej liście jest zaimportowanie naszego sklepu do naszego App.js i wykorzystanie go w naszym projekcie.
import React from 'react'; import Navbar from "./components/navbar"; import ListDisplay from "./components/ListDisplay"; import {ListStore} from './ListStore'; function App() { const store = new ListStore() return ( <div> <Navbar store={store}/> <ListDisplay store={store}/> </div> ); } export default App;
Tutaj zaimportowaliśmy komponenty TitleInput i ListDisplay . Następnie zainicjowaliśmy sklep w naszym App.js
, aby móc przekazać go jako rekwizyty do komponentów TitleInput i ListDisplay .
Zwykle spowoduje to błąd, ponieważ nie pracowaliśmy nad innymi komponentami, więc zróbmy to. Zbudujmy składnik ListDisplay
.
ListDisplay
Ten składnik wyświetla wszystkie dodane przez nas listy, a także automatycznie generuje przycisk usuwania po dodaniu nowej listy.
import React from 'react' import List from "./List"; import { observer } from 'mobx-react'; function ListDisplay(props) { const { deleteList, filteredLists } = props.store return ( <div> <div className="container"> {filteredLists.map(list => ( <List key={list.id} list={list} deleteList={deleteList} /> ))} </div> </div> ) } export default observer(ListDisplay)
Dla tego komponentu stworzyliśmy funkcję ListDisplay
i uczyniliśmy z niej obserwatora, zdestrukturyzowaliśmy również funkcje list
i deletelist
ze sklepu, robiąc to, ułatwiliśmy wtedy przekazywanie jako rekwizyty obiektów.
Następnie mapujemy filteredLists
Listy, aby zwrócić listy, których następnie używamy do budowania indywidualnej listy, przekazując zwrócony element jako właściwości do składnika List .
Po zakończeniu nasz komponent powinien wyglądać tak z dodanymi listami:
Następnie dodaj składniki List i TitleInput .
Komponent listy
Podobnie jak inne nasze komponenty, nasz składnik List
wyeksportuje listę jako obserwator, aby pomóc sklepowi obserwować ją pod kątem zmian.
import React from 'react' import { observer } from 'mobx-react' function List(props) { return ( <div className="card"> <div className="card-body"> <div className="d-flex justify-content-between align-items-center"> <p className={`title ${props.list.done ? "text-secondary" : ""}`}> {props.list.value} </p> <div> <button onClick={props.deleteList.bind(this, props.list)} className="btn btn-danger font-weight-bold py-2 px-5 ml-2"> Delete </button> </div> </div> </div> </div> ) } export default observer(List)
Użyłem bootstrapu do utworzenia kart w pierwszym zestawie divs
, a także wyrównałem ikonę usuwania, aby przejść do prawej strony aplikacji. Najpierw utworzyliśmy komponent karty do obsługi naszej list
, a następnie stworzyliśmy znacznik przycisku dla button
usuwania, który zaakceptuje dwa obiekty tego i przekaże właściwość do listy, która po kliknięciu usunie wybrany element listy z listy na stronie.
Dalej znajduje się nasz TitleInput , który będzie zawierał nasz formularz wprowadzania do dodawania list i tytuł projektu.
TitleInput
Podobnie jak w innych naszych projektach, dodamy funkcję @observer
, aby komponent mógł akceptować rekwizyty z App Store.
import React, { useState } from 'react' import { observer } from 'mobx-react' function Navbar(props) { const [value, setValue] = useState("") const {addList} = props.store const prepareAddList = (e) => { e.preventDefault() addList(value) setValue("") } return ( <div className="container mt-3"> <h1 className="title">List App</h1> <form onSubmit={prepareAddList} className="form-group"> <div className="row ml-lg-2"> <input className="form-control-lg col-12 col-lg-9 col-sm-12 mr-3 border border-secondary" value={value} type="text" onChange={(e) => setValue(e.target.value)} placeholder="Enter list" /> <button className="col-lg-2 col-5 col-sm-5 mt-2 mt-lg-0 mt-sm-2 btn btn-lg btn-success font-weight-bold"> Add to List </button> </div> </form> </div> ) } export default observer(Navbar)
Najpierw zainicjowaliśmy stan początkowy. Korzystając z haków reakcji, dodaliśmy stan początkowy zwany values
, który ustawiamy na pusty ciąg. Używamy tego do przechowywania wartości tego, co jest wprowadzone w polu wejściowym. Aby dowiedzieć się więcej o hakach React, możesz zapoznać się z tym artykułem autorstwa Davida Abioduna.
Następnie wywołaliśmy obiekt dodawania list do sklepu addList
i przekazaliśmy go jako rekwizyty ze sklepu z aplikacjami.
Następnie stworzyliśmy funkcję preparedAddList
do przyjmowania obiektu zdarzenia dla formularzy wejściowych, dodaliśmy również przycisk do ręcznego dodawania list po kliknięciu.
Prawie gotowe, musimy zrestartować nasz serwer projektu, uruchamiając:
yarn start
A nasz TitleInput
powinien wyglądać tak:
Skończyliśmy już ze wszystkimi komponentami naszej aplikacji, więc zamontujmy je w naszym App.js
. W tym celu musimy zaimportować nasze komponenty titleInput
i ListDisplay
. Musimy również zaimportować nasz sklep z komponentu Sklep.
Aby MobX działał w naszej aplikacji, musimy przekazać sklep MobX jako rekwizyty w naszej aplikacji i poszczególne komponenty, aby otrzymały właściwości i funkcje w sklepie.
import React from 'react'; import Navbar from "./components/navbar"; import ListDisplay from "./components/ListDisplay"; import {ListStore} from './ListStore'; function App() { const store = new ListStore() return ( <div> <Navbar store={store}/> <ListDisplay store={store}/> </div> ); } export default App;
Po zakończeniu nasza aplikacja powinna wyglądać tak:
Wniosek
MobX jest świetnym menedżerem stanu, szczególnie dla aplikacji opartych na React, budując naszą aplikację z listą, poznaliśmy podstawowe pojęcia MobX, stan, pochodne i akcje. Działającą wersję tej aplikacji można znaleźć tutaj:
Możesz pójść dalej, używając MobX w następnej kompilowanej aplikacji, która obejmuje zarządzanie stanem. Chciałbym zobaczyć, jakie nowe rzeczy wymyślisz. Możesz przeczytać więcej o MobX i aplikacjach do zarządzania stanem w poniższych odnośnikach.
Zasoby i referencje
- „React Native z MobX — pierwsze kroki”, Nader Dabit, Medium
- „Koncepcje i zasady” MobX (oficjalna dokumentacja)
- „Najlepsze praktyki z React Hooks”, Adeneye David Abiodun, Smashing Magazine