Redux hjelper deg med å håndtere tilstand ved å sette staten opp på et globalt nivå. I den forrige veiledningen hadde vi en god titt på Redux-arkitekturen og Redux-komponentene som for eksempel handlinger, handlingsskapere, butikken og reduksjonsmaskiner.
I dette andre innlegget i serien skal vi styrke vår forståelse av Redux og bygge videre på det vi allerede vet. Vi starter med å skape en realistisk Redux-applikasjon - en kontaktliste - det er mer komplisert enn en grunnteller. Dette vil hjelpe deg å styrke din forståelse av single store og flere reduksjonsbegreper som jeg introduserte i den forrige opplæringen. Senere snakker vi om å binde din Redux-stat med en React-applikasjon og de beste praksiser som du bør vurdere når du lager et prosjekt fra grunnen av.
Men det er greit hvis du ikke har lest det første innlegget. Du bør fortsatt kunne følge med så lenge du kjenner Redux grunnleggende. Koden for opplæringen er tilgjengelig i repo, og du kan bruke det som utgangspunkt.
Vi skal bygge en grunnleggende kontaktliste med følgende funksjoner:
Slik ser vår søknad ut:
Endelig produkt - Kontaktliste VisDet er vanskelig å dekke alt i en strekk. Så i dette innlegget kommer vi til å fokusere på bare Redux-delen av å legge til en ny kontakt og vise den nylig lagt til kontakten. Fra et Redux-perspektiv, vil vi initialisere staten, skape butikken, legge til redusere og tiltak, osv.
I neste veiledning lærer vi hvordan du kobler til React og Redux og sender Redux-handlinger fra en React-frontend. I den siste delen skifter vi vårt fokus mot å lage API-anrop ved hjelp av Redux. Dette inkluderer å hente kontaktene fra serveren og foreta en serverforespørsel mens du legger til nye kontakter. Bortsett fra det, vil vi også opprette en søkefelt-funksjon som lar deg søke i alle eksisterende kontakter.
Du kan laste ned reagent-redux-demo-applikasjonen fra mitt GitHub-lager. Klone repoen og bruk v1 gren som utgangspunkt. De v1 gren er svært lik skape-reagere-app-malen. Den eneste forskjellen er at jeg har lagt til noen få tomme kataloger for å organisere Redux. Her er katalogstrukturen.
. ├── package.json ├── offentlige ├── README.md ├── src │ ├── handlinger │ ├── App.js │ ├── komponenter │ ├── containere │ ├── index.js │ ├── reduksjon │ └─ - lagre └── garn.lock
Alternativt kan du opprette et nytt prosjekt fra bunnen av. Uansett må du ha installert en grunnleggende reaktorkjelett og redux før du kan komme i gang.
Det er en god ide å ha en grov skisse av statens tre først. Etter min mening vil dette spare deg for mye tid i det lange løp. Her er en grov skisse av det mulige statstrøet.
const initialState = kontakter: contactList: [], newContact: navn: ", etternavn:", e-post: ", adresse:", telefon: ", ui: // Alle brukergrensesnittene her. gjem / vis modaler, / / veksleboks etc.
Vår butikk må ha to egenskaper-kontakter
og ui
. Kontakteregenskapen tar seg av alle kontaktrelaterte tilstander, mens ui
håndterer UI-spesifikk tilstand. Det er ingen vanskelig regel i Redux som hindrer deg i å plassere ui
objekt som en delstat av kontakter
. Du er velkommen til å organisere staten din på en måte som føles meningsfull for din søknad.
Kontakteregenskapen har to egenskaper nestet inne i den-kontaktliste
og ny kontakt
. De kontaktliste
er en rekke kontakter, mens ny kontakt
Lagrer kontaktinformasjon midlertidig mens kontaktskjemaet fylles. Jeg skal bruke dette som utgangspunkt for å bygge vår fantastiske kontaktliste-app.
Redux har ingen mening om hvordan du strukturerer søknaden din. Det er noen få populære mønstre der ute, og i denne opplæringen vil jeg kort snakke om noen av dem. Men du bør velge ett mønster og holde fast med det til du forstår helt hvordan alle brikkene er koblet sammen.
Det vanligste mønsteret som du finner, er filen Rails-stil og mappestruktur. Du har flere toppnivå kataloger som de nedenfor:
Bildet nedenfor viser hvordan søknaden vår kan se ut hvis vi følger dette mønsteret:
Rails stilen bør fungere for små og mellomstore applikasjoner. Når appen ditt vokser, kan du imidlertid vurdere å bevege seg mot domenestilstilgangen eller andre populære alternativer som er nært relatert til domenestil. Her vil hver funksjon ha en egen katalog, og alt relatert til den funksjonen (domenet) vil være inne i det. Bildet nedenfor sammenligner de to tilnærmingene, Rails-stil til venstre og domenestil til høyre.
For nå, gå videre og opprett kataloger for komponenter, beholdere, butikk, reduksjonsgir, og handling. La oss starte med butikken.
La oss lage en prototype forde butikk og redusering først. Fra vårt forrige eksempel, er slik butikken vår ser ut:
const store = createStore (reduksjon, kontakter: kontaktliste: [], nyKontakt: , ui: isContactFormHidden: true) const reduer = (tilstand, handling) => bytt "HANDLE_INPUT_CHANGE": break; saken "ADD_NEW_CONTACT": break; saken "TOGGLE_CONTACT_FORM": break; returstatus
Bryteroppstillingen har tre saker som tilsvarer tre handlinger som vi skal skape. Her er en kort forklaring på hva handlingene er ment for.
HANDLE_INPUT_CHANGE
: Denne handlingen blir utløst når brukeren legger inn nye verdier i kontaktskjemaet.ADD_NEW_CONTACT
: Denne handlingen sendes når brukeren sender skjemaet.TOGGLE_CONTACT_FORM
: Dette er en UI-handling som tar seg av å vise / gjemme kontaktskjemaet. Selv om denne naive tilnærmingen fungerer, da søknaden vokser, vil denne teknikken ha noen mangler.
For å fikse problemet med enkeltreduksjon, har Redux en metode som heter kombinere Reducerer som lar deg lage flere reduksjonsverktøy og deretter kombinere dem til en enkelt reduserende funksjon. Funksjonen combineReducers forbedrer lesbarheten. Så jeg skal dele reduksjonsmaskinen i to-a contactsReducer
og a uiReducer
.
I eksemplet ovenfor, Create
aksepterer en valgfri andre argumentet som er den opprinnelige tilstanden. Men hvis vi skal dele reduksjonene, kan vi flytte hele opprinnelige tilstand
til en ny filplassering, si reduksjonsgir / initialState.js. Vi vil da importere en delmengde av opprinnelige tilstand
inn i hver reduksjonsfil.
La oss omstrukturere koden vår for å fikse begge problemene. Først oppretter du en ny fil som heter store / createStore.js og legg til følgende kode:
importer createStore fra 'redux'; importer rootReducer fra '... / reducers /'; / * Opprett en funksjon kalt configureStore * / eksporter standardfunksjon configureStore () return createStore (rootReducer);
Deretter oppretter du en rotreduksjon i reduksjonsgir / index.js som følger:
importer combineReducers fra 'redux' import contactsReducer fra './contactsReducer'; importer uiReducer fra './uiReducer'; const rootReducer = combineReducers (contacts: contactsReducer, ui: uiReducer,) eksporter standard rootReducer;
Til slutt må vi opprette koden for contactsReducer
og uiReducer
.
importer initialstate fra './initialState'; eksporter standardfunksjonskontaktReducer (state = initialState.contacts, action) switch (action.type) / * Legg til kontakter til statussystemet * / tilfelle "ADD_CONTACT": return ... state, contactList: [... state.contactList, state.newContact] / * Håndter inngang for kontaktskjemaet. Lastbelastningen (inngangsendringer) blir fusjonert med det nyeContact-objektet * / tilfellet "HANDLE_INPUT_CHANGE": retur ... state, newContact: ... state.newContact, ... action.payload standard: returstatus;
importer initialstate fra './initialState'; (standard : retur tilstand;
Når du lager reduksjonsutstyr, vær alltid oppmerksom på følgende: En reduksjonsmaskin må ha en standardverdi for sin tilstand, og den må alltid returnere noe. Hvis reduksjonsbryteren ikke følger denne spesifikasjonen, vil du få feil.
Siden vi har dekket mye kode, la oss se på endringene vi har gjort med vår tilnærming:
combineReducers
samtalen er innført for å knytte sammen spaltreduksjonene.ui
objektet håndteres av uiReducer
og tilstanden til kontaktene av contactsReducer
. Create
. I stedet har vi opprettet en egen fil for den som heter initialState.js. Vi importerer opprinnelige tilstand
og deretter angi standardstatus ved å gjøre det state = initialState.ui
. Her er koden for reduksjonsgir / initialState.js fil.
const initialState = kontakter: contactList: [], newContact: navn: ", etternavn:", e-post: ", adresse:", telefon: ",, ui: isContactFormHidden: true
La oss legge til et par handlinger og handlingsskapere for å legge til endringer i håndtering av skjemaer, legge til en ny kontakt og bytte til UI-tilstanden. Hvis du husker, er handlingskapere bare funksjoner som gir tilbake en handling. Legg til følgende kode i handlinger / index.js.
eksport const addContact = () => retur type: "ADD_CONTACT" eksport const handleInputChange = (navn, verdi) => retur type: "HANDLE_INPUT_CHANGE", nyttelast: [navn]: verdi eksporter const toggleContactForm = () => retur type: "TOGGLE_CONTACT_FORM",
Hver handling må returnere en type eiendom. Typen er som en nøkkel som bestemmer hvilken reduksjon blir påkalt og hvordan staten blir oppdatert som svar på den handlingen. Lastbelastningen er valgfri, og du kan faktisk kalle det alt du vil ha.
I vårt tilfelle har vi opprettet tre handlinger.
De TOGGLE_CONTACT_FORM
trenger ikke nyttelast fordi hver gang handlingen utløses, verdien av ui.isContactFormHidden
blir byttet. Boolsk-verdsatt handlinger krever ikke en nyttelast.
De HANDLE_INPUT_CHANGE
Handlingen utløses når formverdien endres. Så for eksempel, tenk at brukeren fyller e-postfeltet. Handlingen mottar deretter "E"
og "[email protected]"
som innganger, og nyttelastet overført til reduksjonsmaskinen er en gjenstand som ser slik ut:
email: "[email protected]"
Reduksjonen bruker denne informasjonen til å oppdatere de aktuelle egenskapene til ny kontakt
stat.
Det neste logiske trinnet er å sende handlingene. Når handlingene er sendt, endres staten som svar på det. For å sende handlinger og for å få oppdatert tilstandstreet, tilbyr Redux visse butikkhandlinger. De er:
avsendelse (handling)
: Sender en handling som potensielt kan utløse en tilstandsendring. getState ()
: Returnerer nåværende tilstandstreet i søknaden din.abonnent (lytteren)
: En forandringslytter som blir kalt hver gang en handling sendes, og en del av statstreet endres. Hodet til index.js fil og importere configureStore
funksjonen og de tre handlingene som vi opprettet tidligere:
Import Reakt fra 'reagere'; importer render fra 'react-dom'; importer app fra './App'; / * Import Redux butikk og handlingene * / import configureStore fra './store/configureStore'; importer toggleContactForm, handleInputChange fra './actions';
Deretter oppretter du en butikk
objekt og legg til en lytter som logger statstreet hver gang en handling sendes:
const store = configureStore (); // Merk at abonnere () returnerer en funksjon for å avregistrere lytteren const unsubscribe = store.subscribe (() => console.log (store.getState ()))
Til slutt, send noen handlinger:
/ * Return isContactFormHidden returnerer false * / store.dispatch (toggleContactForm ()); / * Return isContactFormHidden returnerer false * / store.dispatch (toggleContactForm ()); / * oppdaterer tilstanden til kontaktpersonen.NyeKontakt objekt * / store.dispatch (handleInputChange ('email', '[email protected]')) abonnement;
Hvis alt fungerer riktig, bør du se dette i utviklerkonsollen.
Det er det! I utviklerkonsollen kan du se Redux-butikken bli logget, slik at du kan se hvordan den endres etter hver handling.
Vi har opprettet en Redux-applikasjon for bare-bein til vårt fantastiske kontaktlisteprogram. Vi lærte om reduksjonsmidler, splitter reduksjonsapparater for å gjøre vår app struktur renere, og skrive handlinger for mutating butikken.
Mot slutten av innlegget abonnerte vi på butikken ved hjelp av store.subscribe ()
metode. Teknisk er dette ikke den beste måten å få ting gjort hvis du skal bruke React with Redux. Det er flere optimerte måter å koble reaksjonsfronten til med Redux. Vi vil dekke dem i neste opplæring.