Ce veți învăța

  • Cum se definesc valorile de stare care conțin datele aplicației dvs.
  • Cum să definiți obiecte de acțiune care descriu ce se întâmplă în aplicația dvs.
  • Cum se scrie funcții de reducere care calculează starea actualizată pe baza stării și acțiunilor existente

  • Cunoașterea termenilor și conceptelor cheie Redux, cum ar fi „acțiuni”, „reductoare”, „magazin” și „expediere”. (Vedea Partea 2: Concepte Redux și flux de date pentru explicații despre acești termeni.)

Introducere #

În partea 2: Conceptele și fluxul de date Redux, ne-am uitat la modul în care Redux ne poate ajuta să construim aplicații care pot fi întreținute oferindu-ne un singur loc central pentru a pune starea globală a aplicației. De asemenea, am vorbit despre conceptele de bază Redux, cum ar fi trimiterea obiectelor de acțiune și utilizarea funcțiilor reductor care returnează noi valori de stare.

Acum, că aveți o idee despre ce sunt aceste piese, este timpul să puneți în practică aceste cunoștințe. Vom construi un mic exemplu de aplicație pentru a vedea cum funcționează de fapt aceste piese împreună.

Exemplul de aplicație nu este conceput ca un proiect complet pregătit pentru producție. Scopul este de a vă ajuta să învățați API-urile de bază Redux și modelele de utilizare și să vă îndreptați în direcția corectă folosind câteva exemple limitate. De asemenea, unele dintre primele piese pe care le construim vor fi actualizate ulterior pentru a arăta modalități mai bune de a face lucrurile. Vă rugăm să citiți întregul tutorial pentru a vedea toate conceptele utilizate.

Configurare proiect #

Pentru acest tutorial, am creat un proiect de pornire preconfigurat care are deja configurat React, include unele stiluri implicite și are un API REST fals care ne va permite să scriem solicitări API reale în aplicația noastră. Veți folosi acest lucru ca bază pentru scrierea codului real al aplicației.

Pentru a începe, puteți deschide și furniza acest CodeSandbox:

De asemenea, puteți clona același proiect din această repo Github. După clonarea repo, puteți instala instrumentele pentru proiect cu instalarea npm și porniți-l cu npm start .

Dacă doriți să vedeți versiunea finală a ceea ce vom construi, puteți verifica ramură tutorial-pași, sau consultați versiunea finală din acest CodeSandbox.

Crearea unui nou proiect Redux + React #

După ce ați terminat acest tutorial, probabil că veți dori să încercați să lucrați la propriile dvs. proiecte. Vă recomandăm să utilizați șabloanele Redux pentru Create-React-App ca cel mai rapid mod de a crea un nou proiect Redux + React. Vine cu Redux Toolkit și React-Redux deja configurate, utilizând o versiune modernizată a exemplului de aplicație „contor” pe care l-ați văzut în partea 1. Acest lucru vă permite să treceți direct la scrierea codului de aplicație real, fără a fi nevoie să adăugați pachetele Redux și să configurați magazinul.

Dacă doriți să aflați detalii specifice despre cum să adăugați Redux la un proiect, consultați această explicație:

Explicație detaliată: Adăugarea Redux la un proiect React

Șablonul Redux pentru CRA vine cu Redux Toolkit și React-Redux deja configurate. Dacă configurați un proiect nou de la zero fără șablonul respectiv, urmați acești pași:

  • Adăugați pachetele @ reduxjs/toolkit și react-redux
  • Creați un magazin Redux folosind API configureStore de la RTK și treceți în cel puțin o funcție de reducere
  • Importați magazinul Redux în fișierul punctului de intrare al aplicației dvs. (cum ar fi src/index.js)
  • Înfășurați componenta rădăcină React cu

componentă din React-Redux, cum ar fi:

Explorarea proiectului inițial #

Acest proiect inițial se bazează pe șablonul de proiect standard Create-React-App, cu unele modificări.

Să aruncăm o privire rapidă asupra a ceea ce conține proiectul inițial:

Dacă încărcați aplicația acum, ar trebui să vedeți un mesaj de bun venit, dar restul aplicației este altfel gol.

Cu asta, să începem!

Lansarea aplicației de exemplu Todo #

Exemplul nostru de aplicație va fi o mică aplicație „todo”. Probabil că ați mai văzut exemple de aplicații pentru toate - acestea oferă exemple bune, deoarece ne permit să arătăm cum să facem lucruri precum urmărirea unei liste de articole, gestionarea intrărilor utilizatorilor și actualizarea interfeței de utilizare atunci când aceste date se modifică, care sunt toate lucrurile care se întâmplă în o aplicație normală.

Definirea cerințelor #

Să începem prin a afla cerințele inițiale de afaceri pentru această aplicație:

  • IU ar trebui să fie alcătuită din trei secțiuni principale:
    • O casetă de intrare pentru a permite utilizatorului să introducă textul unui nou element de lucru
    • O listă cu toate elementele existente
    • O secțiune de subsol care arată numărul de todos necompletați și afișează opțiunile de filtrare
  • Elementele din lista Todo trebuie să aibă o casetă de selectare care comută starea lor „finalizată”. De asemenea, ar trebui să putem adăuga o etichetă de categorie codificată pentru culori pentru o listă predefinită de culori și să ștergem elementele de lucru.
  • Contorul ar trebui să pluralizeze numărul de todos activi: "0 articole", "1 articol", "3 articole" etc.
  • Ar trebui să existe butoane pentru a marca toate toate ca terminate și pentru a șterge toate toate finalizate, eliminându-le
  • Ar trebui să existe două modalități de filtrare a tuturor afișate în listă:
    • Filtrare bazată pe afișarea tuturor „Toate”, „Active” și „Finalizate”
    • Filtrarea se bazează pe selectarea uneia sau mai multor culori și afișarea oricărui tuturor a căror etichetă corespunde acelor culori

Vom adăuga mai multe cerințe mai târziu, dar acest lucru este suficient pentru a ne începe.

Scopul final este o aplicație care ar trebui să arate astfel:

reducere

Proiectarea valorilor de stat #

Unul dintre principiile de bază ale React și Redux este că interfața dvs. de utilizare ar trebui să se bazeze pe starea dvs.. Deci, o abordare a proiectării unei aplicații este să ne gândim mai întâi la starea necesară pentru a descrie modul în care funcționează aplicația. Este, de asemenea, o idee bună să încercați să vă descrieți interfața de utilizare cu cât mai puține valori în stare, astfel încât există mai puține date de care aveți nevoie pentru a urmări și a actualiza.

Conceptual, există două aspecte principale ale acestei aplicații:

  • Lista reală a elementelor de lucru curente
  • Opțiunile curente de filtrare

De asemenea, va trebui să ținem evidența datelor pe care utilizatorul le tastează în caseta de introducere „Adăugați totul”, dar acest lucru este mai puțin important și vom face față asta mai târziu.

Pentru fiecare articol todo, trebuie să stocăm câteva informații:

  • Textul introdus de utilizator
  • Steagul boolean care spune dacă este finalizat sau nu
  • O valoare de identificare unică
  • O categorie de culori, dacă este selectată

Comportamentul nostru de filtrare poate fi probabil descris cu câteva valori enumerate:

  • Stare finalizată: „Toate”, „Activă” și „Finalizată”
  • Culori: „Roșu”, „Galben”, „Verde”, „Albastru”, „Portocaliu”, „Violet”

Privind aceste valori, putem spune, de asemenea, că toate sunt „starea aplicației” (datele de bază cu care funcționează aplicația), în timp ce valorile de filtrare sunt „starea UI” (o stare care descrie ce face aplicația corect acum). Poate fi util să ne gândim la aceste tipuri diferite de categorii pentru a ajuta la înțelegerea modului în care sunt folosite diferitele părți de stat.

Proiectarea structurii de stat #

Cu Redux, starea aplicației noastre este întotdeauna păstrată în obiecte și tablouri JavaScript simple. Asta înseamnă că este posibil să nu puneți alte lucruri în starea Redux - fără instanțe de clasă, tipuri JS încorporate, cum ar fi Hartă/Set promisiune/dată, funcții sau orice altceva care nu este o informație JS simplă.

Valoarea stării rădăcină Redux este aproape întotdeauna un obiect JS simplu, cu alte date imbricate in interiorul acestuia.

Pe baza acestor informații, ar trebui să putem descrie tipurile de valori pe care trebuie să le avem în starea noastră Redux:

  • În primul rând, avem nevoie de o serie de obiecte de element todo. Fiecare articol trebuie să aibă următoarele câmpuri:
    • id: un număr unic
    • text: textul introdus de utilizator
    • finalizat: un steag boolean
    • culoare: o categorie opțională de culoare
  • Apoi, trebuie să descriem opțiunile noastre de filtrare. Trebuie să avem:
    • Valoarea curentă a filtrului „finalizat”
    • O serie de categorii de culori selectate în prezent

Deci, iată cum ar putea arăta un exemplu de stare a aplicației noastre:

Este important să rețineți că este în regulă să aveți alte valori de stat în afara Redux!. Acest exemplu este suficient de mic până acum încât să avem de fapt toată starea noastră în magazinul Redux, dar așa cum vom vedea mai târziu, unele date nu trebuie păstrate în Redux (de exemplu, „este derulantul deschis?” Sau „valoarea curentă a unui formular introdus”).

Acțiuni de proiectare #

Acțiuni sunt obiecte JavaScript simple care au un câmp tip. Ca menționat mai devreme, vă puteți gândi la o acțiune ca la un eveniment care descrie ceva ce s-a întâmplat în aplicație.

În același mod în care am proiectat structura de stat pe baza cerințelor aplicației, ar trebui să putem, de asemenea, să venim cu o listă cu unele dintre acțiunile care descriu ceea ce se întâmplă:

  • Adăugați o nouă intrare de lucru pe baza textului introdus de utilizator
  • Comutați starea finalizată a unei activități
  • Selectați o categorie de culori pentru un lucru
  • Ștergeți totul
  • Marcați-le pe toate ca terminate
  • Ștergeți toate finalizate toate
  • Alegeți o altă valoare de filtrare „finalizată”
  • Adăugați un nou filtru de culoare
  • Eliminați un filtru de culoare

În mod normal, punem toate datele suplimentare necesare pentru a descrie ceea ce se întâmplă în câmpul action.payload. Acesta ar putea fi un număr, un șir sau un obiect cu mai multe câmpuri în interior.

Magazinului Redux nu îi pasă care este textul real al câmpului action.type. Cu toate acestea, propriul cod se va uita la action.type pentru a vedea dacă este necesară o actualizare. De asemenea, veți privi frecvent șiruri de tipuri de acțiune în extensia Redux DevTools în timp ce depanați pentru a vedea ce se întâmplă în aplicația dvs. Deci, încercați să alegeți tipuri de acțiuni care să fie lizibile și să descrie clar ce se întâmplă - va fi mult mai ușor să înțelegeți lucrurile atunci când le priviți mai târziu!

Pe baza acelei liste de lucruri care se pot întâmpla, putem crea o listă de acțiuni pe care aplicația noastră le va folosi:

În acest caz, acțiunile au în primul rând o singură bucată de date în plus, astfel încât să o putem pune direct în câmpul action.payload. Am fi putut împărți comportamentul filtrului de culoare în două acțiuni, una pentru „adăugat” și una pentru „eliminat”, dar în acest caz o vom face ca o acțiune cu un câmp suplimentar în interior specific pentru a arăta că putem avea obiecte ca o sarcină utilă de acțiune.

Ca și datele de stat, acțiunile ar trebui să conțină cea mai mică cantitate de informații necesare pentru a descrie ce s-a întâmplat.

Reductoare de scriere #

Acum, că știm cum arată structura noastră de stat și acțiunile noastre, este timpul să scriem primul nostru reductor.

Reductoare sunt funcții care iau starea curentă și o acțiune ca argumente și returnează un nou rezultat de stare. Cu alte cuvinte, (stare, acțiune) => newState .

Crearea Root Reducer #

O aplicație Redux are într-adevăr o singură funcție de reducere: funcția „reductor de rădăcină” pe care îl veți trece la createStore mai târziu. Funcția de reducere a rădăcinii este responsabilă de gestionarea tuturor acțiunilor care sunt expediate și de calculul a ceea ce ar trebui să fie de fiecare dată întregul rezultat al stării noi.

Să începem prin a crea un fișier reducer.js în folderul src, alături de index.js și App.js .

Fiecare reductor are nevoie de o anumită stare inițială, așa că vom adăuga câteva intrări false pentru a ne începe. Apoi, putem scrie o schiță pentru logica din interiorul funcției reductor: