10 vinkkiä paremmalle Redux-arkkitehtuurille

Mandariini-ankka - Malcolm Carlaw (CC-BY-2.0)

Kun aloin käyttää Reaktia, Reduxia ei ollut. Oli vain Flux-arkkitehtuuri ja noin tusina kilpailevaa toteutusta.

Nyt Reaktan tiedonhallinnassa on kaksi selkeää voittajaa: Redux ja MobX, ja jälkimmäinen ei ole edes Flux-toteutus. Redux on kiinni niin paljon, että sitä ei enää käytetä vain Reaktoriin. Löydät Redux-arkkitehtuurin toteutuksia muille kehyksille, mukaan lukien Angular 2. Katso esimerkiksi ngrx: store.

Sivuhuomautus: MobX on siisti, ja valitsen sen todennäköisesti Reduxin yli yksinkertaisille käyttöliittymille, koska se on vähemmän monimutkainen ja vähemmän selkeä. On kuitenkin joitain Reduxin tärkeitä piirteitä, joita MobX ei anna sinulle, ja on tärkeää ymmärtää, mitkä nämä ominaisuudet ovat, ennen kuin päätät, mikä sopii projektiisi.
Sivupuolen huomautus: Relay ja Falcor ovat muita mielenkiintoisia ratkaisuja valtionhallintaan, mutta toisin kuin Redux ja MobX, niiden on oltava vastaavasti GraphQL: n ja Falcor Server -tuki, ja kaikki Relay-tilat vastaavat jotakin palvelimen pysyvää tietoa. AFAIK, kumpikaan ei tarjoa hyvää tarinaa vain asiakaspuolen ohimenevälle valtionhallinnalle. Saatat pystyä nauttimaan molempien eduista sekoittamalla ja sovittamalla Relay tai Falcor Reduxin tai MobX: n kanssa, erottamalla vain asiakastila ja palvelimen pysyvä tila. Bottom line: Asiakkaalla ei tällä hetkellä ole selvää yksittäistä voittoa valtionhallinnasta. Käytä oikeaa työkalua käsillä olevaan työhön.

Reduxin luoja Dan Abramov järjesti pari hienoa kurssia aiheesta:

  • Reduxin käyttöönotto
  • Rakennussovellukset idioomaattisen Reduxin kanssa

Molemmat ovat upeita vaiheittaisia ​​opetusohjelmia, jotka selittävät Reduxin perusteet, mutta tarvitset myös korkeamman tason ymmärryksen, jotta saat Reduxista kaiken hyödyn.

Seuraavat vinkit auttavat sinua rakentamaan parempia Redux-sovelluksia.

1. Ymmärrä Reduxin edut

Reduxilla on muutama tärkeä tavoite, jotka sinun on pidettävä mielessä:

  1. Deterministinen näkymä tekee
  2. Deterministinen valtion lisääntyminen

Determinismi on tärkeä sovelluksen testattavuudelle ja vikojen diagnosoinnille ja korjaamiselle. Jos sovelluksen näkymät ja tila ovat epädeterministisiä, on mahdotonta tietää, ovatko näkymät ja tila aina voimassa. Saatat jopa sanoa, että epädeterminismi on sinänsä vika.

Mutta jotkut asiat ovat luontaisesti epädeterministisiä. Esimerkiksi käyttäjän syöttämisen ja verkko I / O: n ajoitus. Joten miten voimme koskaan tietää, toimiiko koodimme todella? Helppo: eristäminen.

Reduxin päätarkoitus on eristää valtionhallinta I / O-sivuvaikutuksista, kuten kuvan näyttämisestä tai verkon käytöstä. Kun sivuvaikutukset on eristetty, koodista tulee paljon yksinkertaisempi. Yrityksen logiikan ymmärtäminen ja testaaminen on paljon helpompaa, kun kaikki ei ole sekaantunut verkkopyyntöihin ja DOM-päivityksiin.

Kun näkymäsovellus on eristetty verkon I / O: sta ja tilapäivitykset, voit saavuttaa deterministisen näkymämuodostuksen, mikä tarkoittaa: kun sama tila on, näkymä näyttää aina saman tuloksen. Se eliminoi sellaisten ongelmien mahdollisuuden, kuten kilpailuolosuhteet, jotka johtuvat asynkronisista tavaroista, jotka pyyhkäisevät satunnaisesti näkymäsi bittejä, tai silpomalla oman tilan bittejä, kun näkymäsi on renderointiprosessissa.

Kun aloittelija harkitsee näkymän luomista, he saattavat ajatella: "Tämä bitti tarvitsee käyttäjämallin, joten aion käynnistää asynk-pyynnön hakeaksesi sen, ja kun lupaus on ratkaistu, päivitän käyttäjän komponentin nimellä. Se vähän siellä vaatii tehtäviä, joten haemme sen, ja kun lupaus on ratkaistu, silmukkaamme niitä ja vedetään ne näytölle. "

Tässä lähestymistavassa on muutama suuri ongelma:

  1. Sinulla ei ole koskaan kaikkia tietoja, joita tarvitset täydellisen näkymän tuottamiseksi milloin tahansa. Et oikeasti noutaa tietoja, ennen kuin komponentti alkaa suorittaa asiansa.
  2. Eri noutaustehtäviä voi tulla eri aikoina, hienovaraisesti muuttamalla järjestystä, jolla asiat tapahtuvat näkymänmuutosjärjestyksessä. Jotta renderöintisekvenssi todella ymmärrettäisiin, sinun on tiedettävä jotain, jota et voi ennustaa: kunkin asynk-pyynnön kesto. Pop-tietokilpailu: Mikä tekee yllä olevassa skenaariossa ensin käyttäjän komponentin tai tehtävät? Vastaus: Se on kilpailu!
  3. Joskus tapahtuman kuuntelijat mutatoivat näkymän tilan, mikä saattaa laukaista toisen renderoinnin, mikä edelleen vaikeuttaa sekvenssiä.

Tärkein ongelma tietojen tallentamisessa näkymätilaan ja asynkitapahtumien kuuntelijoille pääsyn muokata kyseistä näkymätilaa on seuraava:

”Ei-määritelmä = rinnakkaiskäsittely + jaettu tila”
~ Martin Odersky (Scalan suunnittelija)
Tiedonhaku, tietojen manipulointi ja näkymähahmot ovat resepti aikamatkaaville spagetteille.

Tiedän, että kuulostaa kinda coolilta B-elokuvan sci-fi-muodolta, mutta usko minua, aikamatkustavat spagetit ovat pahimman makuisen tyyppisiä!

Mitä flux-arkkitehtuuri tekee, on tiukka erottelu ja järjestys, joka noudattaa näitä sääntöjä joka kerta:

  1. Ensinnäkin pääsemme tunnettuun, kiinteään tilaan ...
  2. Sitten teemme näkymän. Mikään ei voi muuttaa tämän renderöintisilmukan tilaa uudelleen.
  3. Kun sama tila, näkymä muuttuu aina samalla tavalla.
  4. Tapahtuman kuuntelijat kuuntelevat käyttäjän syötteitä ja verkkopyyntöjen käsittelijöitä. Kun he saavat ne, toimitukset lähetetään kauppaan.
  5. Kun toiminto lähetetään, tila päivitetään uuteen tunnettuun tilaan ja sekvenssi toistuu. Vain lähetetyt toimet voivat koskea tilaa.

Se on pähkinänkuoressa: Yksisuuntainen tiedonkulkuarkkitehtuuri käyttöliittymällesi:

Flux-arkkitehtuuri

Flux-arkkitehtuurilla näkymä kuuntelee käyttäjän syötettä, kääntää ne toimintaobjekteiksi, jotka lähetetään kauppaan. Kauppa päivittää sovelluksen tilan ja ilmoittaa näkymän renderoitavaksi uudelleen. Tietenkin, näkymä on harvoin ainoa lähde ja tapahtumia, mutta se ei ole ongelma. Lisätapahtuman kuuntelijat lähettävät toimintaobjekteja, kuten näkymä:

Tärkeää on, että Flux-tilan päivitykset ovat tapahtumakohtaisia. Sen sijaan, että vain kutsutaan päivitysmenetelmää tilalle tai manipuloidaan suoraan arvoa, toimintaobjektit lähetetään kauppaan. Toimintaobjekti on tapahtumarekisteri. Voit ajatella sitä kuin pankkitapahtumaa - tietueen tehdystä muutoksesta. Kun teet talletuksen pankkiisi, 5 minuutin vastainen saldosi ei lopu. Sen sijaan tapahtumahistoriaan lisätään uusi saldo. Toimintaobjektit lisää tapahtumahistorian sovellustilaan.

Toimintaobjektit näyttävät tältä:

Mitä toimintoobjektit antavat, on kyky pitää käynnissä oleva loki kaikista valtion tapahtumista. Tätä lokia voidaan käyttää tilan toistamiseen deterministisella tavalla, tarkoittaen:

Kun otetaan huomioon sama alkutila ja samat tapahtumat samassa järjestyksessä, saat aina saman tilan seurauksena.

Tällä on tärkeitä vaikutuksia:

  1. Helppo testatavuus
  2. Helppo kumoa / tee uudelleen
  3. Aikamatkan virheenkorjaus
  4. Kestävyys - Vaikka tila tuhoutuisi, jos sinulla on tietue jokaisesta tapahtumasta, voit tuottaa sen.

Kuka ei halua hallita tilaa ja aikaa? Transaktionaalinen tila antaa sinulle aikamatkustavia suurvaltoja:

Redux dev -työkalujen historian liukusäädin

2. Jotkin sovellukset eivät tarvitse Reduxia

Jos käyttöliittymän työnkulku on yksinkertainen, kaikki tämä voi olla ylikuormitttua. Jos teet tic-tac-toe-peliä, tarvitsetko todella peruuttaa / tehdä uudelleen? Pelit kestävät harvoin yli minuutin. Jos käyttäjä ruuvataan kiinni, voit pelin nollata ja antaa heidän aloittaa alusta.

Jos:

  • Käyttäjien työnkulut ovat yksinkertaisia
  • Käyttäjät eivät tee yhteistyötä
  • Sinun ei tarvitse hallita palvelinpuolen tapahtumia (SSE) tai verkkopaketteja
  • Haet tietoja yhdestä tietolähteestä katselua kohti

Voi olla, että sovelluksen tapahtumasekvenssi on todennäköisesti riittävän yksinkertainen, että tapahtumatilan edut eivät ole ylimääräisen vaivan arvoisia.

Ehkä sinun ei tarvitse fluksoida sovellustasi. Tällaisiin sovelluksiin on olemassa paljon yksinkertaisempi ratkaisu. Katso MobX.

Sovelluksesi monimutkaisuuden kasvaessa ja näkymätilan hallinnan monimutkaisuuden kasvaessa tapahtumatilan arvo kasvaa sen mukana, eikä MobX tarjoa tapahtumien tilanhallintaa.

Jos:

  • Käyttäjien työnkulut ovat monimutkaisia
  • Sovelluksessasi on laaja valikoima käyttäjän työnkulkuja (ota huomioon sekä tavalliset käyttäjät että järjestelmänvalvojat)
  • Käyttäjät voivat tehdä yhteistyötä
  • Käytät verkkopistorasioita tai SSE: tä
  • Lataat tietoja useista päätepisteistä rakentaaksesi yhden näkymän

Sinusta voisi olla tarpeeksi hyötyä tapahtumatilamallista, jotta se olisi vaivan arvoista. Redux saattaa sopia sinulle hyvin.

Mitä tekemistä verkkoliittimillä ja SSE: llä on tähän? Kun lisäät asynkronisen I / O-lähteitä, on vaikea ymmärtää sovelluksen tapahtumia määrittelemättömän valtionhallinnan avulla. Deterministinen tila ja tilatapahtumien tietue yksinkertaistavat radikaalisti tämänkaltaisia ​​sovelluksia.

Mielestäni useimpiin suuriin SaaS-tuotteisiin liittyy ainakin muutama monimutkainen käyttöliittymän työnkulku, ja niiden pitäisi käyttää tapahtumien tilanhallintaa. Useimpien pienten apuohjelmien ja yksinkertaisten prototyyppien ei pitäisi olla. Käytä työhön oikeaa työkalua.

3. Ymmärrä pelkistimet

Redux = flux + toiminnallinen ohjelmointi

Flux määrää yksisuuntaisen tiedonkulun ja tapahtumatilan toimintaobjekteilla, mutta ei sano mitään toimintaobjektien käsittelemisestä. Sieltä Redux tulee sisään.

Reduxin valtionhallinnan ensisijainen rakennusosa on pelkistystoiminto. Mikä on reduktoritoiminto?

Toiminnallisessa ohjelmoinnissa yleistä apuohjelmaa `vähentää ()` tai `taita ()` käytetään vähentämistoiminnon käyttämiseen jokaisessa arvoluettelon arvossa yhden lähtöarvon keräämiseksi. Tässä on esimerkki summausvähennyksestä, joka on sovellettu JavaScript-taulukkoon nimellä Array.prototype.reduce () `:

Sen sijaan, että toimitettaisiin ryhmillä, Redux käyttää pelkistimiä toimintaobjektien virtaan. Muista, että toimintaobjekti näyttää tältä:

Muutetaan yllä oleva summausvähennysyksikkö Redux-tyyliseksi reduktoriksi:

Nyt voimme soveltaa sitä joihinkin testitoimenpiteisiin:

4. Pelkistimien on oltava puhtaita toimintoja

Deterministisen tilantoiston saavuttamiseksi pelkistimien on oltava puhtaita toimintoja. Ei poikkeuksia. Puhdas funktio:

  1. Samaa tuloa käytettäessä palauttaa aina saman tulosteen.
  2. Ei haittavaikutuksia.

Tärkeää JavaScriptiä, kaikki ei-primitiiviset objektit siirretään toimintoihin viitteinä. Toisin sanoen, jos siirrät objektin ja mutatoit sitten suoraan objektin ominaisuuden, objekti muuttuu myös toiminnon ulkopuolella. Se on sivuvaikutus. Et voi tietää funktion kutsumisen täydellistä merkitystä tietämättä myös sen objektin koko historiaa, jonka ohitsit. Se on huono asia.

Pelkistimien tulisi palauttaa uusi esine sen sijaan. Voit tehdä sen esimerkiksi esimerkiksi Object.assign ({}, state, {thingToChange}) `.

Taulukon parametrit ovat myös viitteitä. Et voi vain `.push ()` uusia kohteita taulukkoon pelkistimessä, koska `.push ()` on mutaatio-operaatio. Samoin ovat `.pop ()`, `.shift ()`, `.unshift ()`, `.reverse ()`, `.splice ()` ja kaikki muut mutaattorimenetelmät.

Jos haluat olla turvassa taulukkojen kanssa, sinun on rajoitettava tilassa suorittamasi toiminnot turvallisten lisälaitteiden menetelmiin. Käytä `.push ()`: n sijasta `.concat ()`.

Katso tätä ADD_CHAT-tapausta tässä chat-pelkistimessä:

Kuten näette, uusi objekti luodaan nimellä "Object.assign ()", ja liitämme taulukkoon nimellä ".concat ()" sijasta ".push ()".

Henkilökohtaisesti en halua olla huolissani tilan vahingossa tapahtuvasta muuntumisesta, joten viime aikoina olen kokeillut käyttää muuttumattomien tietojen sovellusliittymiä Reduxin kanssa. Jos tilani on muuttumaton objekti, minun ei tarvitse edes katsoa koodia tietääkseni, että esinettä ei ole vahingossa muunnettu. Tulin tähän johtopäätökseen työskennellytsi ryhmässä ja löysin virheitä vahingossa tapahtuvista valtion mutaatioista.

Pelkillä toiminnoilla on paljon muutakin kuin tämä. Jos aiot käyttää Reduxia tuotantosovelluksiin, tarvitset todella hyvän käsityksen siitä, millaiset puhtaat toiminnot ovat, ja muista asioista, jotka sinun on pidettävä mielessä (kuten ajankäyttö, kirjaaminen ja satunnaislukut). Lisätietoja siitä on kohdassa ”Hallitse JavaScript-haastattelu: Mikä on puhdas toiminto?”.

5. Muista: pelkistimien on oltava ainoa totuuden lähde

Kaikilla sovelluksesi tiloilla tulisi olla yksi totuuden lähde, mikä tarkoittaa, että tila on tallennettu yhteen paikkaan, ja missä tahansa muualla tätä tilaa tarvitaan, tulisi päästä tilaan viittaamalla yksittäiseen totuuden lähteeseen.

On totta, että eri asioilla on erilaisia ​​totuuden lähteitä. Esimerkiksi URL voi olla yksittäinen totuuden lähde käyttäjän pyyntöpolulle ja URL-parametreille. Ehkä sovelluksessasi on määrityspalvelu, joka on ainoa totuuden lähde API-URL-osoitteillesi. Se on hieno. Kuitenkin…

Kun tallennat mitä tahansa tilaa Redux-kauppaan, kaikki tilaan pääsy tulee tehdä Reduxin kautta. Tämän periaatteen noudattamatta jättäminen voi johtaa vanhentuneeseen tietoon tai sellaisiin jaettuihin tilamutaatiovirheisiin, joiden ratkaisemiseksi keksittiin Flux ja Redux.

Toisin sanoen, ilman yhtä totuuden lähteen periaatetta, menetät mahdollisesti:

  • Deterministinen näkymämuodostus
  • Deterministinen tilan toisto
  • Helppo kumoa / tee uudelleen
  • Aikamatkan virheenkorjaus
  • Helppo testatavuus

Joko Redux tai älä tee Redux-tilaasi. Jos teet sen puoliväliin, voit kumota kaikki Reduxin edut.

6. Käytä vakioita toimintotyypeille

Haluan varmistaa, että toiminnot on helppo jäljittää pelkistimeen, joka käyttää niitä, kun tarkastelet toimintahistoriaa. Jos kaikilla toimillasi on lyhyet, yleisnimet, kuten `CHANGE_MESSAGE`, on vaikeampaa ymmärtää sovelluksesi tapahtumia. Jos toimintotyypeillä on kuitenkin kuvaavammat nimet, kuten `CHAT :: CHANGE_MESSAGE`, on tietysti paljon selvempää mitä tapahtuu.

Lisäksi, jos teet kirjoitusvirheen ja lähetät määrittelemättömän toimintavakion, sovellus heittää virheen ilmoittaakseen virheestä. Jos teet kirjoitusvirheen toimintotyyppisellä merkkijonolla, toiminto epäonnistuu hiljaa.

Kaikkien pelkistimen toimintotyyppien pitäminen yhdessä paikassa tiedoston yläosassa voi myös auttaa sinua:

  • Pidä nimet johdonmukaisina
  • Ymmärrä nopeasti pelkistimen sovellusliittymä
  • Katso, mitä muutos vetopyynnöissä on

7. Irrota toimintalogiikka lähetyssoittajista toimintojen luojien avulla

Kun sanon ihmisille, että he eivät voi tuottaa henkilötodistuksia tai napata nykyistä aikaa pelkistimessä, minusta tulee hauska ilme. Jos katselet näyttöä epäilyttävästi heti, voit olla varma: et ole yksin.

Joten missä on hyvä paikka käsitellä epäpuhdasta logiikkaa toistamatta sitä kaikkialla, missä sinun on käytettävä toimintoa? Toiminnan luojana.

Toiminnan luojalla on myös muita etuja:

  • Pidä toimintotyypin vakiot koteloituna reduktoritiedostoosi, joten sinun ei tarvitse tuoda niitä muualle.
  • Tee joitain laskelmia tuloista ennen toiminnan lähettämistä.
  • Vähennä kattilalevyä

Käytämme toiminnon luojaa luomaan `ADD_CHAT` -toimintaobjekti:

Kuten yllä näet, käytämme cuidia luomaan satunnaisia ​​tunnuksia jokaiselle chat-viestille ja `Date.now ()` aikaleiman luomiseksi. Molemmat ovat epäpuhtaita toimintoja, joita ei ole turvallista suorittaa pelkistimessä - mutta on täysin ok suorittaa ne toiminnan luomisessa.

Vähennä kattilolevyä toiminnan luomisen avulla

Jotkut ihmiset ajattelevat, että toiminta-luojien käyttäminen lisää kattilalevyn projektiin. Päinvastoin, aiot nähdä, kuinka käytän niitä vähentämään huomattavasti kattilalevyä reduktoreissani.

Vinkki: Jos tallennat vakio-, pelkistys- ja toimiluohjelmasi kaikki samaan tiedostoon, vähennät kattilalevyn tarvetta, kun tuot ne erillisistä sijainneista.

Kuvittele, että haluamme lisätä chat-käyttäjän kyvyn mukauttaa käyttäjän nimeään ja saatavuustilaa. Voisimme lisätä pari toimintatyyppistä käsittelijää pelkistimeen seuraavasti:

Suuremmissa pelkistimissä tämä voi kasvaa paljon kattilolevyksi. Paljon rakentamasi pelkistimet voivat olla paljon monimutkaisempia, paljon redundantteja koodeja. Entä jos voimme romahtaa kaikki yksinkertaiset ominaisuudenvaihtotoimet yhdessä?

Osoittautuu, että se on helppoa:

Jopa ylimääräisen välilyönnin ja lisäkommentin kanssa tämä versio on lyhyempi - ja tämä on vain kaksi tapausta. Säästöt voivat todella kasvattaa.

Eikö kytkin… tapaus ole vaarallinen? Näen kaatumisen!

Olet ehkä lukenut jostain, että "vaihto" -lausuntoja tulisi välttää, etenkin jotta voimme välttää vahingossa tapahtuvan kaatumisen ja koska tapausluettelo voi paistua. Olet ehkä kuullut, että sinun ei pitäisi koskaan käyttää kaatumista tahallaan, koska vahingossa tapahtuvien kaatumisvirheiden löytäminen on vaikeaa. Se on kaikki hyviä neuvoja, mutta ajatellaan huolellisesti yllä mainittuja vaaroja:

  • Pelkistimet ovat kompostoitavia, joten kotelon paisuminen ei ole ongelma. Jos tapausluettelosi on liian suuri, katkaise palat ja siirrä ne erillisiin pienentäjiin.
  • Jokainen tapaus elin palaa takaisin, joten vahingossa tapahtuvaa kaatumista ei tulisi koskaan tapahtua. Yhdessäkään ryhmittyneessä putoamiskotelossa ei saa olla muita kappaleita kuin ne, jotka suorittavat saaliin.

Redux käyttää "kytkin .. tapaa" hyvin. Muutan virallisesti neuvojani asiasta. Niin kauan kuin noudatat yllä olevia yksinkertaisia ​​sääntöjä (pidä kytkimet pieninä ja keskittyneinä ja palaa jokaisesta tapauksesta omalla rungollaan), kytkinlausekkeet ovat hienoja.

Olet ehkä huomannut, että tämä versio vaatii erilaisen hyötykuorman. Täällä toiminta-tekijät tulevat sisään:

Kuten voitte nähdä, nämä toimien luojat tekevät käännöksen argumentien ja tilan muodon välillä. Mutta se ei ole muuta, mitä he tekevät ...

8. Käytä ES6-parametrien oletuksia allekirjoitusdokumentaatioon

Jos käytät Tern.js-sovellusta toimittajalaajennuksen kanssa (saatavana suosituille toimittajille, kuten Sublime Text ja Atom), se lukee kyseiset ES6-oletustehtävät ja päättelee toimintojen luojat vaaditun käyttöliittymän, joten kun soitat heille, voit saada automaattisen ja automaattisen täydennyksen. Tämä vie kognitiivisen kuormituksen kehittäjille, koska heidän ei tarvitse muistaa vaadittua hyötykuormatyyppiä tai tarkistaa lähdekoodia unohtaessaan.

Jos et käytä tyyppiviittauslaajennusta, kuten Tern, TypeScript tai Flow, sinun pitäisi olla.

Huomaa: Mieluummin luotan funktion allekirjoituksessa näkyvien oletusmääritysten tarjoamiin päätelmiin kuin tyyppihuomautuksiin, koska:

  1. Sinun ei tarvitse käyttää Flow- tai TypeScriptiä saadaksesi sen toimimaan: Käytät sen sijaan tavallista JavaScriptiä.
  2. Jos käytät TypeScriptiä tai Flowa, merkinnät ovat tarpeettomia oletusmäärityksissä, koska sekä TypeScript että Flow johtavat tyypin oletusmäärityksestä.
  3. Minusta se on paljon luettavissa, kun syntaksimelu on vähemmän.
  4. Saat oletusasetukset, mikä tarkoittaa, että vaikka et estä CI: n rakentamista tyyppivirheisiin (olisit yllättynyt, monet projektit eivät ole), sinulla ei koskaan ole vahingossa "määrittelemätöntä" parametria, joka piilee koodi.

9. Käytä valitsimia laskettuun tilaan ja irrottamiseen

Kuvittele, että olet rakentamassa chat-sovellusten historian monimutkaisinta chat-sovellusta. Olet kirjoittanut 500 000 riviä koodia, ja sitten tuoteryhmä asettaa sinulle uuden ominaisuusvaatimuksen, joka pakottaa sinut muuttamaan valtion tietorakennetta.

Ei tarvitse paniikkia. Olit riittävän fiksu irrottamaan loput sovellus valtiosi muodosta valitsimilla. Luoti: väistetty.

Luon melkein jokaiselle kirjoittamalle reduktorille valitsimen, joka vie vain kaikki muuttujat, joita tarvitsen näkymän rakentamiseksi. Katsotaanpa miltä se voisi näyttää yksinkertaiselle chat-vähennyslaitteellemme:

vienti const getViewState = tila => tila;

Kyllä tiedän. Se on niin yksinkertaista, ettei se edes ole syytä arvoinen. Saatat ajatella, että olen nyt hullu, mutta muistatko sen luodin, jonka vältimme ennen? Entä jos haluaisimme lisätä lasketun tilan, kuten täydellisen luettelon kaikista käyttäjistä, jotka ovat keskustelleet tämän istunnon aikana? Kutsutaan sitä "äskettäin aktiivisiksi käyttäjiksi".

Nämä tiedot on jo tallennettu nykyiseen tilaan - mutta ei tavalla, joka on helppo tarttua. Mennään eteenpäin ja tartu se `getViewState ()`:

Jos laitat kaiken lasketun tilan valitsimiin, sinun:

  1. Vähennä pelkistimien ja komponenttien monimutkaisuutta
  2. Irrota loput sovelluksesi valtionmuodosta
  3. Noudata totuuden ainoan lähteen periaatetta, jopa reduktorissasi

10. Käytä TDD: Kirjoita testit ensin

Monissa tutkimuksissa on verrattu testin ensin testi jälkikäteen -menetelmiin eikä lainkaan testeihin. Tulokset ovat selkeät ja dramaattiset: Suurin osa tutkimuksista osoittaa lähetysvirheiden vähentyneen 40–80% testien kirjoittamisen tuloksena ennen ominaisuuksien käyttöönottoa.

TDD voi tehokkaasti leikata lähetysvirhesi tiheyden puoleen, ja väitteen tueksi on runsaasti todisteita.

Kirjoittaessani tämän artikkelin esimerkkejä aloitin ne kaikki yksikkötesteillä.

Jotta vältettäisiin herkät testit, olen perustanut seuraavat tehtaat, jotka olen aikaisemmin antanut odotuksia:

Huomaa, että nämä molemmat tarjoavat oletusarvot, mikä tarkoittaa, että voin ohittaa ominaisuudet erikseen luodakseni vain tietyt testit, joista olen kiinnostunut.

Näin käytin niitä:

Huomaa: Käytän teippiä yksikkötesteihin yksinkertaisuuden vuoksi. Minulla on myös 2–3 vuoden kokemus Mochasta ja Jasmineista ja sekalainen kokemus monista muista puitteista. Sinun pitäisi pystyä mukauttamaan nämä periaatteet mihin tahansa valittuun kehykseen.

Huomaa tyyli, jonka olen kehittänyt kuvaamaan sisäkkäisiä testejä. Todennäköisesti Jasmine- ja Mocha-taustani takia haluan aluksi kuvailemalla testaamaani komponenttia ulkoisessa lohkossa ja sitten sisäisissä lohkoissa kuvailemalla sitä, mitä siirron komponenttiin. Sisällä teen yksinkertaisia ​​vastaavuusväitteitä, jotka voit tehdä testikirjastosi `deepEqual ()` tai `toEqual ()` -toiminnoilla.

Kuten huomaat, käytän eristettyjä testitilaa ja tehdastoimintoja apuohjelmien, kuten `beforeEach ()` ja `afterEach ()`, sijasta, jota vältän, koska ne voivat rohkaista kokemattomia kehittäjiä käyttämään jaettua tilaa testipaketissa (se on huono) .

Kuten todennäköisesti arvasit, minulla on kolme erilaista testiä jokaiselle reduktorille:

  1. Suorat reduktoritestit, joista olet juuri nähnyt esimerkin. Nämä pääasiassa testaavat, että pelkistin tuottaa odotetun oletustilan.
  2. Toiminnan luonti testit, joissa testataan jokainen toiminnan luonti soveltamalla pelkistintä toimintaan käyttämällä jotain ennalta määrättyä tilaa lähtökohtana.
  3. Valitsintesti, jolla testataan valitsimia varmistaakseen, että kaikki odotetut ominaisuudet ovat olemassa, mukaan lukien lasketut ominaisuudet odotettuilla arvoilla.

Olet jo nähnyt pelkistimen testin. Katsotaanpa joitain muita esimerkkejä.

Toiminnan luoja -testit

Tämä esimerkki on mielenkiintoinen muutamasta syystä. `AddChat ()` -toiminnan luoja ei ole puhdas. Tämä tarkoittaa, että ellet ylitä arvojen ylityksiä, et voi asettaa erityistä odotusta kaikille tuotetuille ominaisuuksille. Käsitelläksemme tätä putken avulla, jota käytän toisinaan välttämään ylimääräisten muuttujien luomista, joita en todellakaan tarvitse. Käytin sitä sivuuttaa luodut arvot. Varmistamme edelleen, että ne ovat olemassa, mutta emme välitä, mitkä arvot ovat. Huomaa, etten edes tarkista tyyppiä. Luotamme tyypin päätelmiin ja oletusarvoihin huolehtia siitä.

Putki on toiminnallinen apuohjelma, jonka avulla voit siirtää joitain tuloarvoja toimintojen sarjan kautta, jotka kumpikin ottavat edellisen funktion lähdön ja muuntavat sen jollain tavalla. Käytän `lodash / fp / pipe` -nimisestä ludash-putkesta, joka on alias sanalle` lodash / flow`. Mielenkiintoista on, että `pipe ()` itsessään voidaan luoda pelkistystoiminnolla:

Olen taipuvainen käyttämään `pipe ()` paljon myös reduktoritiedostoissa tilanmuutosten yksinkertaistamiseksi. Kaikki tilamuutokset ovat viime kädessä datavirtoja, jotka liikkuvat yhdestä dataesityksestä toiseen. Sitä varten "pipe ()" on hyvä.

Huomaa, että toiminnan luonti antaa meille myös ohittaa kaikki oletusarvot, joten voimme siirtää tietyt tunnukset ja aikaleimat ja testata tiettyjä arvoja.

Valintatestit

Viimeiseksi testaamme tilanvalitsimet ja varmistamme, että lasketut arvot ovat oikeat ja että kaikki on niin kuin pitäisi olla:

Huomaa, että tässä testissä olemme käyttäneet `Array.prototype.reduce ()` vähentääkseen muutamalla esimerkillä `addChat ()` -toimintoja. Yksi Redux-reduktorien hienoista asioista on, että ne ovat vain säännöllisiä reduktoritoimintoja, mikä tarkoittaa, että voit tehdä niiden kanssa mitä tahansa, mitä tekisit minkä tahansa muun reduktoritoiminnon kanssa.

"Odotettu" arvo tarkistaa, että kaikki chat-objektimme ovat lokissa ja että äskettäin aktiiviset käyttäjät on lueteltu oikein.

Ei paljon muuta sanottavaa siitä.

Redux-säännöt

Jos käytät Reduxia oikein, saat merkittäviä etuja:

  • Poista ajoitusriippuvuusvirheet
  • Ota deterministinen näkymän esitys käyttöön
  • Ota deterministinen tilan toisto käyttöön
  • Ota helppo kumoa / tee uudelleen -ominaisuudet
  • Yksinkertaista virheenkorjausta
  • Tule aikamatkustajaksi

Mutta jotta kaikki toimisi, sinun on muistettava joitain sääntöjä:

  • Pelkistimien on oltava puhtaita toimintoja
  • Pelkistimien on oltava heidän valtionsa ainoa totuuden lähde
  • Pelkistimen tilan tulisi aina olla sarjoitettavissa
  • Pelkistimen tila ei saisi sisältää toimintoja

Muista myös:

  • Jotkut sovellukset eivät tarvitse Reduxia
  • Käytä vakioita toimintotyypeille
  • Käytä toimintojen luojaa erottamaan toimintalogiikka lähettävistä soittajista
  • Käytä ES6-parametrien oletusarvoja itse kuvaaviin allekirjoituksiin
  • Käytä valitsimia laskettuun tilaan ja irrottamiseen
  • Käytä aina TDD: tä!

Nauttia!

Oletko valmis tasoittamaan Redux-taitojasi DevAnywhere-ohjelmalla?

Opi edistynyt toiminnallinen ohjelmointi, reagoi ja Redux 1: 1-ohjauksella. Lifetime Access -jäsenet, tutustu toiminnalliseen ohjelmointiin ja Redux-oppitunteihin. Katso ehdottomasti Shotgun-sarjaa ja aja ampumapistoolia kanssani, kun rakennan oikeita sovelluksia Reaktin ja Reduxin kanssa.

https://devanywhere.io/

Eric Elliott on kirjoittanut ”Programming JavaScript Applications” -sovelluksen (O’Reilly) ja on DevAnywhere.io: n perustaja. Hän on osallistunut ohjelmistokokemuksiin Adobe Systemsille, Zumba Fitnessille, The Wall Street Journalille, ESPN: lle, BBC: lle ja parhaimmille äänittäjille, kuten Usher, Frank Ocean, Metallica ja monille muille.

Hän työskentelee missä vain haluaa, maailman kauneimman naisen kanssa.