Kuinka käyttää fluxia tilan hallintaan ReactJS: ssä - selitetty esimerkillä

Jos olet alkanut työskennellä ReactJS: n kanssa äskettäin, saatat miettiä, kuinka hallita tilaa Reactissa niin, että sovelluksesi voi laajentaa.

Tämän valtionhallintakysymyksen ratkaisemiseksi monet yritykset ja ihmiset ovat kehittäneet erilaisia ​​ratkaisuja. ReactJS: n kehittänyt Facebook keksi Flux- nimisen ratkaisun .

Olet ehkä kuullut Redux jos olet työskennellyt etupäässä teknologiaan, kuten angularjs tai EmberJS . ReactJS: llä on myös kirjasto Reduxin toteuttamiseksi.

Mutta ennen Reduxin oppimista kehotan sinua käymään läpi Fluxin ja ymmärtämään sen. Sen jälkeen kokeile Reduxiä. Sanon tämän, koska Redux on edistyneempi versio Fluxista. Jos Fluxin käsitteet ovat selkeät, voit oppia reduxin ja integroida sen sovellukseesi.

Mikä on virtaus?

Flux käyttää yksisuuntaista tiedonsiirtomallia tilanhallinnan monimutkaisuuden ratkaisemiseksi. Muista, että se ei ole kehys - pikemminkin se on malli, jolla pyritään ratkaisemaan valtionhallintakysymys.

Mietitkö, mikä on vialla nykyisellä MVC-kehyksellä? Kuvittele, että asiakkaasi sovellus kasvaa. Sinulla on vuorovaikutus monien mallien ja näkymien välillä. Miltä se näyttää?

Komponenttien välinen suhde monimutkaistuu. Sovelluksen skaalaaminen on vaikeaa. Facebook kohtasi saman asian. Tämän ongelman ratkaisemiseksi he suunnittelivat yhden suunnan tietovirran .

Kuten yllä olevasta kuvasta näet, Fluxissa käytetään paljon komponentteja. Käydään läpi kaikki komponentit yksi kerrallaan.

Näkymä: tämä komponentti hahmottaa käyttöliittymän. Aina kun siinä esiintyy käyttäjän vuorovaikutusta (kuten tapahtuma), se laukaisee toiminnon. Myös kun myymälä ilmoittaa näkymälle jonkinlaisesta muutoksesta, se renderoi itsensä uudelleen. Esimerkiksi, jos käyttäjä napsauttaa Lisää- painiketta.

Toimi: tämä hoitaa kaikki tapahtumat. Näkymäkomponentti välittää nämä tapahtumat. Tätä kerrosta käytetään yleensä API-puheluiden soittamiseen. Kun toiminto on suoritettu, se lähetetään lähettäjällä. Toiminto voi olla esimerkiksi lisätä viesti, poistaa viesti tai mikä tahansa muu käyttäjän vuorovaikutus.

Tapahtuman lähettämisen hyötykuorman yhteinen rakenne on seuraava:

{ actionType: "", data: { title: "Understanding Flux step by step", author: "Sharvin" } }

ActionType-avain on pakollinen, ja välittäjä käyttää sitä välittämään päivityksiä liittyvään kauppaan. On myös tunnettua käytäntöä käyttää vakioita pitämään actionType-avaimen arvon nimi niin, ettei kirjoitusvirheitä tapahdu. Tiedot sisältävät tapahtumatiedot, jotka haluamme lähettää toiminnasta kauppaan. Tämän avaimen nimi voi olla mikä tahansa.

Dispatcher: tämä on keskitin ja singleton-rekisteri. Se lähettää hyötykuorman Actionsista Storeen. Varmista myös, ettei CSS-tehosteita ole, kun toiminto lähetetään kauppaan. Se varmistaa, ettei mitään muuta tapahdu ennen kuin tietokerros on suorittanut käsittely- ja tallennusoperaatiot.

Otetaan huomioon, että tällä komponentilla on järjestelmässä liikenteenohjain. Se on keskitetty takaisinsoittoluettelo. Se kutsuu soittopyynnön ja lähettää toiminnosta saamansa hyötykuorman.

Tämän komponentin ansiosta tietovirta on ennustettavissa. Jokainen toiminto päivittää tietyn myymälän soittopyynnöllä, joka on rekisteröity välittäjälle.

Store: tämä pitää sovelluksen tilan ja on tämän mallin tietokerros. Älä pidä sitä MVC: n mallina. Sovelluksella voi olla yksi tai useita sovelluskauppoja. Kaupat päivitetään, koska niillä on soittopyyntö, joka on rekisteröity välittäjän kautta.

Solmun tapahtumien lähettäjää käytetään myymälän päivittämiseen ja päivityksen lähettämiseen katselua varten. Näkymä ei koskaan päivitä sovelluksen tilaa suoraan. Se päivitetään myymälän muutosten vuoksi.

Tämä on vain osa Fluxista, joka voi päivittää tiedot. Kaupassa toteutetut käyttöliittymät ovat seuraavat:

  1. EventEmitter laajennetaan ilmoittaa, että tallentaa tiedot on päivitetty.
  2. Kuuntelijat, kuten addChangeListener ja removeChangeListener, lisätään.
  3. emitChange käytetään muutoksen lähettämiseen.

Harkitse yllä olevaa kaaviota, jossa on enemmän kauppoja ja näkymiä. Silti kuvio ja tiedonkulku ovat samat. Tämä johtuu siitä, että tämä on yksisuuntainen ja ennustettavissa oleva datavirta, toisin kuin MVC tai kaksisuuntainen sidonta. Tämä parantaa tietojen yhdenmukaisuutta ja virheen löytäminen on helpompaa .

No, Flux tuo seuraavat keskeiset edut taulukkoon yksisuuntaisen tiedonkulun avulla:

  1. Koodista tulee melko selkeä ja helppo ymmärtää.
  2. Helposti testattava yksikötestillä.
  3. Skaalautuvia sovelluksia voidaan rakentaa.
  4. Ennakoitava tietovirta.
Huomaa: Fluxin ainoa haittapuoli on, että on olemassa jokin kattilalevy, joka meidän on kirjoitettava. Kattilalevyn lisäksi on vähän koodia, joka meidän on kirjoitettava, kun lisätään komponentteja olemassa olevaan sovellukseen.

Sovelluksen malli

Rakennamme Viestit-sivun, jotta voit oppia fluxin toteuttamisesta ReactJS: ssä. Tässä näytämme kaikki viestit. Sovellusmalli on saatavana tältä sitoutumiselta. Käytämme tätä mallina Fluxin integroimiseksi sen päälle.

Kloonaa koodi tästä sitoutumisesta käyttämällä seuraavaa komentoa:

git clone //github.com/Sharvin26/DummyBlog.git
git checkout 0d56987b2d461b794e7841302c9337eda1ad0725

Tarvitsemme reagoivan reitittimen-dom- ja bootstrap- moduulin. Asenna nämä paketit seuraavalla komennolla:

npm install [email protected] [email protected] 

Kun olet valmis, näet seuraavan sovelluksen:

Ymmärtääksemme Fluxin yksityiskohtaisesti, toteutamme vain GET- viestisivun. Kun se on tehty, huomaat, että prosessi on sama POST , EDIT ja DELETE .

Täällä näet seuraavan hakemistorakenteen:

+-- README.md +-- package-lock.json +-- package.json +-- node_modules +-- .gitignore +-- public | +-- index.html +-- src | +-- +-- components | +-- +-- +-- common | +-- +-- +-- +-- NavBar.js | +-- +-- +-- PostLists.js | +-- +-- pages | +-- +-- +-- Home.js | +-- +-- +-- NotFound.js | +-- +-- +-- Posts.js | +-- index.js | +-- App.js | +-- db.json
Huomaa: Olemme lisänneet tähän db.json  tiedoston. Tämä on nuken datatiedosto. Koska emme halua rakentaa sovellusliittymiä ja sen sijaan keskittyä Fluxiin, haemme tiedot tästä tiedostosta.

Sovelluksemme peruskomponentti on index.js. Täällä olemme säädettiin, App.jssisällä index.htmlalle julkisesta hakemistosta käyttämällä tekevät ja getElementById menetelmiä. Tätä App.jskäytetään reittien määrittämiseen.

Lisäämme myös NavBar- komponentin toisen päälle, joten se on saatavana kaikille komponenteille.

Sisällä sivut hakemistoon meillä on 3 kuvaa => Home.js, Posts.jsja NotFound.js. Home.js  käytetään vain näyttämään Koti-komponentti. Kun käyttäjä reitittää URL-osoitteeseen, jota ei ole, NotFound.jsrenderöi.

Se Posts.json pääkomponentti ja sitä käytetään tietojen hakemiseen db.jsontiedostosta. Se välittää nämä tiedot komponenttihakemistonPostLists.js alle . Tämä komponentti on tyhmä komponentti ja se käsittelee vain käyttöliittymää. Se hakee tiedot rekvisiittaa pääkomponentiltaan ( ) ja näyttää ne korttien muodossa.Posts.js

Nyt kun olemme selvillä siitä, miten blogisovelluksemme toimii, aloitamme integroimalla Fluxin sen päälle.

Fluxin integrointi

Asenna Flux seuraavalla komennolla:

npm install [email protected]

Fluxin integroimiseksi sovellukseemme jaamme tämän osan 4 osioon:

  1. Lähettäjä
  2. Toiminnot
  3. Kaupat
  4. Näytä

Huomaa: Koko koodi on saatavana tästä arkistosta.

Lähettäjä

Luo ensin kaksi uutta kansioita nimeltä toimia ja kaupat alle src hakemistoon. Sen jälkeen luo tiedosto, joka on nimetty appDispatcher.js  samaan src-hakemistoon.

Huomaa: Tästä lähtien kaikilla Fluxiin liittyvillä tiedostoilla on Camel-kotelo, koska ne eivät ole ReactJS-komponentteja.

Siirry kohtaan appDispatcher.jsja kopioi ja liitä seuraava koodi:

import { Dispatcher } from "flux"; const dispatcher = new Dispatcher(); export default dispatcher; 

Here we are importing the Dispatcher from the flux library that we installed, creating a new object and exporting it so that our actions module can use it.

Actions

Now go to the actions directory and create two files named actionTypes.js and postActions.js.  In the actionTypes.js we will define the constants that we require in postActions.js and store module.

The reason behind defining constants is that we don't want to make typos. You don't have to define constants but it is generally considered a good practice.

// actionTypes.js export default { GET_POSTS: "GET_POSTS", }; 

Now inside the postActions.js, we will retrieve the data from db.json and use the dispatcher object to dispatch it.

//postActions.js import dispatcher from "../appDispatcher"; import actionTypes from "./actionTypes"; import data from "../db.json"; export function getPosts() { dispatcher.dispatch({ actionTypes: actionTypes.GET_POSTS, posts: data["posts"], }); } 

Here in the above code, we have imported the dispatcher object, actionTypes constant, and data. We are using a dispatcher object's dispatch method to send the data to the store. The data in our case will be sent in the following format:

{ actionTypes: "GET_POSTS", posts: [ { "id": 1, "title": "Hello World", "author": "Sharvin Shah", "body": "Example of blog application" }, { "id": 2, "title": "Hello Again", "author": "John Doe", "body": "Testing another component" } ] }

Stores

Now we need to build the store which will act as a data layer for storing the posts. It will have an event listener to inform the view that something has changed, and will register using dispatcher with the actions to get the data.

Go to the store directory and create a new file called postStore.js.  Now first, we will import EventEmitter from the Events package. It is available in the NodeJS by default. We will also import the dispatcher object and actionTypes constant file here.

import { EventEmitter } from "events"; import dispatcher from "../appDispatcher"; import actionTypes from "../actions/actionTypes"; 

We will declare the constant of the change event and a variable to hold the posts whenever the dispatcher passes it.

const CHANGE_EVENT = "change"; let _posts = [];

Now we will write a class that extends the EventEmitter as its base class. We will declare the following methods in this class:

addChangeListener: It uses the NodeJS EventEmitter.on. It adds a change listener that accepts the callback function.

removeChangeListener: It uses the NodeJS EventEmitter.removeListener. Whenever we don't want to listen for a specific event we use the following method.

emitChange: It uses the NodeJS EventEmitter.emit. Whenever any change occurs, it emits that change.

This class will also have a method called getPosts which returns the variable _posts that we have declared above the class.

Below the variable declaration add the following code:

class PostStore extends EventEmitter { addChangeListener(callback) { this.on(CHANGE_EVENT, callback); } removeChangeListener(callback) { this.removeListener(CHANGE_EVENT, callback); } emitChange() { this.emit(CHANGE_EVENT); } getPosts() { return _posts; } }

Now create the store object of our PostStore class. We will export this object so that we can use it in the view.

const store = new PostStore();

After that, we will use the dispatcher's register method to receive the payload from our Actions component.

To register for the specific event, we need to use the actionTypes value and determine which action has occurred and process the data accordingly. Add the following code below the object declaration:

dispatcher.register((action) => { switch (action.actionTypes) { case actionTypes.GET_POSTS: _posts = action.posts; store.emitChange(); break; default: } });

We will export the object from this module so others can use it.

export default store;

View

Now we will update our view to send the event to postActions  whenever our Posts page is loaded and receive the payload from the postStore. Go to Posts.js under the pages directory. You'll find the following code inside the useEffect method:

useEffect(() => { setposts(data["posts"]); }, []);

We will change how our useEffect reads and updates the data. First, we will use the addChangeListener method from the postStore class and we will pass an onChange callback to it. We will set the postsstate value to have a return value of the getPosts method from the postStore.js file.

At the start, the store will return an empty array as there is no data available. So we will call a getPostsmethod from the postActions.js. This method will read the data and pass it to the store. Then the store will emit the change and addChangeListener will listen to the change and update the value of the posts  in its onChange callback.

If this seems confusing don't worry – check out the flow chart below which makes it easier to understand.

Remove the old code and update the following code inside Posts.js:

import React, { useState, useEffect } from "react"; import PostLists from "../components/PostLists"; import postStore from "../stores/postStore"; import { getPosts } from "../actions/postActions"; function PostPage() { const [posts, setPosts] = useState(postStore.getPosts()); useEffect(() => { postStore.addChangeListener(onChange); if (postStore.getPosts().length === 0) getPosts(); return () => postStore.removeChangeListener(onChange); }, []); function onChange() { setPosts(postStore.getPosts()); } return ( ); } export default PostPage; 

Here you'll find that we have also removed the import and also we are using setPosts inside our callback instead of useEffect method. The return () => postStore.removeChangeListener(onChange); is used to remove the listener once the user leaves that page.

Tämän jälkeen siirry blogisivulle ja huomaat, että blogisovelluksemme toimii. Ainoa ero on, että nyt sen sijaan, että lukisimme tiedot useEffect- menetelmässä, luemme ne toiminnoissa, tallennamme ne kauppaan ja lähetämme ne komponentteille, jotka sitä tarvitsevat.

Kun käytät varsinaista sovellusliittymää, huomaat, että sovellus lataa tiedot sovellusliittymästä kerralla ja tallentaa ne kauppaan. Kun käymme uudelleen samalla sivulla, huomaat, että mitään API-kutsua ei enää tarvita. Voit seurata sitä Chrome-kehittäjäkonsolin lähde-välilehdessä.

Ja olemme valmiita! Toivon, että tämä opetusohjelma on tehnyt Fluxin ajatuksesta selkeämmän ja pystyt käyttämään sitä projekteissasi.

Ota rohkeasti yhteyttä minuun Twitterissä ja Githubissa.