Dacă ați început să lucrați recent la ReactJS, s-ar putea să vă întrebați cum să gestionați starea în React, astfel încât aplicația dvs. să poată fi scalată.

Pentru a rezolva această problemă de gestionare a statului, multe companii și oameni au dezvoltat diverse soluții. Facebook, care a dezvoltat ReactJS, a venit cu o soluție numită Flux.

Poate ai auzit de asta Redux dacă ați lucrat la tehnologia front-end cum ar fi AngularJS sau EmberJS. ReactJS are, de asemenea, o bibliotecă pentru implementarea Redux.

Dar, înainte de a învăța Redux, v-aș sfătui să treceți prin Flux și să îl înțelegeți. După aceea, încercați Redux. Spun asta pentru că Redux este o versiune mai avansată a Flux. Dacă conceptele Flux sunt clare, atunci puteți învăța redux-ul și îl puteți integra în aplicația dvs.

Ce este fluxul?

Flux folosește un model de flux de date unidirecțional pentru a rezolva complexitatea managementului de stat. Amintiți-vă că nu este un cadru – mai degrabă este mai degrabă un model care vizează rezolvarea problemei managementului de stat.

Vă întrebați ce este în neregulă cu cadrul MVC existent? Imaginați-vă că aplicația clientului dvs. se extinde. Aveți interacțiune între multe modele și vizualizări. Cum ar arăta?

Cum se foloseste Flux pentru a gestiona starea in ReactJS
Credit: Imagine de pe Facebook F8 Flux Event

Relația dintre componente se complică. Devine dificil de dimensionat aplicația. Facebook s-a confruntat cu aceeași problemă. Pentru a rezolva această problemă au arhitectat un Flux de date unidirecțional.

1611685269 783 Cum se foloseste Flux pentru a gestiona starea in ReactJS
Credit: Imagine din Flux Doc de pe Facebook

După cum puteți vedea din imaginea de mai sus, există o mulțime de componente utilizate în Flux. Să parcurgem toate componentele una câte una.

Vedere: această componentă redă interfața de utilizare. Ori de câte ori apare o interacțiune cu utilizatorul (ca un eveniment), atunci declanșează acțiunea. De asemenea, atunci când Magazinul informează Vizualizarea că s-au produs unele modificări, acesta se redistribuie singur. De exemplu, dacă un utilizator face clic pe Adăuga buton.

Acțiune: aceasta se ocupă de toate evenimentele. Aceste evenimente sunt transmise de componenta de vizualizare. Acest strat este utilizat în general pentru a efectua apeluri API. Odată ce acțiunea este efectuată, aceasta este expediată folosind Dispatcher. Acțiunea poate fi ceva precum adăugarea unei postări, ștergerea unei postări sau orice altă interacțiune cu utilizatorul.

Structura comună a sarcinii utile pentru expedierea unui eveniment este următoarea:

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

Cheia actionType este obligatorie și este utilizată de dispecerat pentru a transmite actualizări magazinului aferent. Este, de asemenea, o practică cunoscută să utilizați constante pentru a menține numele valorii pentru cheia actionType, astfel încât să nu apară greșeli de tipar. Datele conțin informațiile despre eveniment pe care dorim să le trimitem de la Acțiune la magazin. Numele acestei chei poate fi orice.

Dispecer: acesta este hub-ul central și registrul singleton. Expediază sarcina utilă din Actions to Store. De asemenea, se asigură că nu există efecte în cascadă atunci când o acțiune este expediată în magazin. Se asigură că nu se întâmplă nicio altă acțiune înainte ca stratul de date să finalizeze operațiunile de procesare și stocare.

Luați în considerare faptul că această componentă are un controler de trafic în sistem. Este o listă centralizată de apeluri de apel. Invocă apelarea și transmite sarcina utilă pe care a primit-o din acțiune.

Datorită acestei componente, fluxul de date este previzibil. Fiecare acțiune actualizează magazinul specific cu apelul de apel care este înregistrat la dispecerat.

Magazin: aceasta deține starea aplicației și este un strat de date al acestui model. Nu îl considerați ca pe un model de la MVC. O aplicație poate avea unul sau mai multe magazine de aplicații. Magazinele sunt actualizate deoarece au un apel invers care este înregistrat folosind dispeceratul.

Emițătorul de evenimente al nodului este utilizat pentru actualizarea magazinului și difuzarea actualizării pentru vizualizare. Vizualizarea nu actualizează niciodată în mod direct starea aplicației. Este actualizat din cauza modificărilor aduse magazinului.

Aceasta este doar o parte din Flux care poate actualiza datele. Interfețele implementate în magazin sunt după cum urmează:

  1. EventEmitter este extins pentru a informa vizualizarea faptului că datele magazinului au fost actualizate.
  2. Ascultătorilor le place addChangeListener și removeChangeListener sunt adăugate.
  3. emitChange este folosit pentru a emite schimbarea.

Luați în considerare diagrama de mai sus, cu mai multe magazine și vizualizări. Totuși, modelul și fluxul de date vor fi aceleași. Acest lucru se datorează faptului că aceasta este o direcție unică și un flux de date previzibil, spre deosebire de legarea MVC sau Two-way. Acest lucru îmbunătățește consistența datelor si este mai ușor de găsit eroarea.

1611685269 694 Cum se foloseste Flux pentru a gestiona starea in ReactJS
Flux de date Flux

Ei bine, Flux aduce următoarele beneficii cheie în tabel cu ajutorul flux de date unidirecțional:

  1. Codul devine destul de clar și ușor de înțeles.
  2. Ușor de testat folosind Unit Test.
  3. Pot fi construite aplicații scalabile.
  4. Flux de date previzibil.

Notă: Singurul dezavantaj al Flux-ului este că trebuie să scriem o boilerplate. În afară de boilerplate, există puțini coduri pe care trebuie să le scriem atunci când adăugăm componente la aplicația existentă.

Șablon de aplicație

Pentru a afla cum să implementăm fluxul în ReactJS, vom construi o pagină Postări. Aici vom afișa toate postările. Șablonul de aplicație este disponibil aici comite. Vom folosi acest lucru ca șablon pentru integrarea Flux deasupra acestuia.

Pentru a clona codul din acest commit, utilizați următoarea comandă:

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

Vom avea nevoie de un react-router-dom și bootstrap modul. Pentru a instala aceste pachete, utilizați următoarea comandă:

npm install react-router-dom@5.0.0 bootstrap@4.3.1  

După ce ați terminat, veți vedea următoarea aplicație:

Cum se foloseste Flux pentru a gestiona starea in ReactJS
DummyBlog

Pentru a înțelege Flux în detaliu, vom implementa numai OBȚINE pagina de postări. Odată ce ați terminat, veți realiza că procesul este același pentru POST, EDITAȚI | × și ȘTERGE.

Aici veți vedea următoarea structură de directoare:

+-- 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

Notă: Am adăugat aici un db.json fişier. Acesta este un fișier de date fals. Deoarece nu vrem să construim API-uri și să ne concentrăm în schimb pe Flux, vom prelua datele din acest fișier.

Componenta de bază a aplicației noastre este index.js. Aici am redat App.js în interiorul index.html în directorul public folosind face și getElementById metode. App.js este utilizat pentru configurarea rutelor.

De asemenea, adăugăm NavBar componentă în partea de sus a celuilalt, astfel încât va fi disponibil pentru toate componentele.

În interiorul pagini director avem 3 fișiere => Home.js, Posts.js, și NotFound.js. Home.js este pur și simplu utilizat pentru a afișa componenta Acasă. Atunci când un utilizator direcționează către o adresă URL care nu există, atunci NotFound.js redă.

Posts.js este componenta părinte și este utilizată pentru a obține date de la db.json fişier. Transmite aceste date către PostLists.js sub componente director. Această componentă este o componentă stupidă și se ocupă doar de interfața de utilizare. Obține datele ca recuzită de la componenta sa părinte (Posts.js) și îl afișează sub formă de cărți.

Acum, că suntem clari despre modul în care funcționează aplicația noastră de blog, vom începe cu integrarea Flux deasupra acesteia.

Integrarea Fluxului

Instalați Flux utilizând următoarea comandă:

npm install flux@3.1.3

Pentru a integra Flux în aplicația noastră vom împărți această secțiune în 4 subsecțiuni:

  1. Dispecer
  2. Acțiuni
  3. Magazine
  4. Vedere

Notă: Codul complet este disponibil aici repertoriu.

Dispecer

Mai întâi, creați două foldere noi numite acțiuni și magazine sub src director. După aceea creați un fișier numit appDispatcher.js sub același director src.

Notă: De acum vor avea toate fișierele legate de Flux Carcasă de cămilă deoarece nu sunt componente ReactJS.

Du-te la appDispatcher.js și copiați-lipiți următorul cod:

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

Aici importăm Dispecerul din biblioteca de fluxuri pe care am instalat-o, creăm un obiect nou și îl exportăm, astfel încât modulul nostru de acțiuni să îl poată utiliza.

Acțiuni

Acum du-te la acțiuni director și creați două fișiere numite actionTypes.js și postActions.js. În actionTypes.js vom defini constantele în care avem nevoie postActions.js și modul de stocare.

Motivul care stă la baza definirii constantelor este că nu vrem să facem greșeli de scriere. Nu trebuie să definiți constante, dar este în general considerată o bună practică.

// actionTypes.js

export default {
    GET_POSTS: "GET_POSTS",
};

Acum în interiorul postActions.js, vom prelua datele de la db.json și utilizați obiectul dispecer pentru a-l expedia.

//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"],
    });
}

Aici, în codul de mai sus, am importat obiectul dispecer, constanta actionTypes și datele. Folosim metoda de expediere a unui obiect de dispecer pentru a trimite datele către magazin. Datele din cazul nostru vor fi trimise în următorul 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"
        }
    ]
}

Magazine

Acum trebuie să construim magazinul care va acționa ca un stratul de date pentru depozitarea stâlpilor. Va avea un ascultător de evenimente pentru a informa punctul de vedere că s-a schimbat ceva și se va întâmpla Inregistreaza-te folosind dispecerul cu acțiunile pentru obținerea datelor.

Accesați directorul magazinului și creați un fișier nou numit postStore.js. Acum, mai întâi, vom importa EventEmitter din pachetul Evenimente. Este disponibil în mod implicit în NodeJS. De asemenea, vom importa aici obiectul dispecer și fișierul constant actionTypes.

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

Vom declara constanta Schimbare eveniment și o variabilă pentru a ține posturile ori de câte ori dispecerul îl trece.

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

Acum vom scrie o clasă care extinde EventEmitter ca clasă de bază. Vom declara următoarele metode în această clasă:

addChangeListener: Folosește NodeJS EventEmitter.on. Se adaugă un ascultător de schimbări care acceptă funcția de apel invers.

removeChangeListener: Folosește NodeJS EventEmitter.removeListener. Ori de câte ori nu dorim să ascultăm un anumit eveniment, folosim următoarea metodă.

emitChange: Folosește NodeJS EventEmitter.emit. Ori de câte ori apare o modificare, aceasta emite această schimbare.

Această clasă va avea și o metodă numită getPosts care returnează variabila _posts pe care le-am declarat deasupra clasei.

Sub declarația variabilă adăugați următorul cod:

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;
    }
}

Acum creați fișierul store obiect al clasei noastre PostStore. Vom exporta acest obiect astfel încât să-l putem folosi în vizualizare.

const store = new PostStore();

După aceea, vom folosi dispeceratul Inregistreaza-te metoda de a primi sarcina utilă din componenta noastră Acțiuni.

Pentru a ne înregistra la evenimentul specific, trebuie să folosim actionTypes evaluează și determină ce acțiune a avut loc și procesează datele în consecință. Adăugați următorul cod sub declarația obiectului:

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

Vom exporta obiectul din acest modul pentru ca alții să îl poată folosi.

export default store;

Vedere

Acum ne vom actualiza vizualizarea pentru a trimite evenimentul postActions ori de câte ori pagina noastră de mesaje este încărcată și primește sarcina utilă de la PostStore. Mergi la Posts.js sub pagini director. Veți găsi următorul cod în interiorul useEffect metodă:

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

Vom schimba modul în care useEffect citește și actualizează datele. În primul rând, vom folosi addChangeListener din clasa postStore și vom trece un onChange callback la acesta. Vom stabili posts valoare de stat pentru a avea o valoare de returnare a getPosts metoda din postStore.js fişier.

La început, magazinul va returna o matrice goală, deoarece nu există date disponibile. Deci vom apela a getPosts metoda din postActions.js. Această metodă va citi datele și le va transmite magazinului. Apoi magazinul va emite schimbarea și addChangeListener va asculta schimbarea și va actualiza valoarea posts în onChange suna inapoi.

Dacă acest lucru pare confuz, nu vă faceți griji – consultați diagrama de mai jos, care vă face mai ușor de înțeles.

1611685269 198 Cum se foloseste Flux pentru a gestiona starea in ReactJS

Eliminați vechiul cod și actualizați următorul cod din interior 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 (
        <div>
            <PostLists posts={posts} />
        </div>
    );
}

export default PostPage;

Aici veți descoperi că am eliminat și importul și, de asemenea, îl folosim setPosts în interiorul apelului nostru în loc de metoda useEffect. return () => postStore.removeChangeListener(onChange); este folosit pentru a elimina ascultătorul odată ce utilizatorul părăsește acea pagină.

Cu aceasta accesați pagina Blog și veți descoperi că aplicația noastră pentru blog funcționează. Singura diferență este că acum, în loc să citiți datele din useEffect metoda o citim în acțiuni, o stocăm în magazin și o trimitem la componentele care o necesită.

Când utilizați API-ul real, veți descoperi că aplicația încarcă datele din API o dată și le stochează în magazin. Când vom revizita aceeași pagină, veți observa că nu este necesar din nou apel API. O puteți monitoriza în fila sursă din consola pentru dezvoltatori Chrome.

Și am terminat !! Sper că acest tutorial a făcut mai clară ideea Flux și o veți putea folosi în proiectele dvs.

Simțiți-vă liber să vă conectați cu mine pe Stare de nervozitate și Github.