10 patarimų dėl geresnės „Redux“ architektūros

Mandarinų antis - Malcolmas Carlovas (CC-BY-2.0)

Kai aš pradėjau naudoti „React“, nebuvo „Redux“. Buvo tik „Flux“ architektūra ir apie keliolika konkuruojančių jos įgyvendinimų.

Dabar yra du aiškūs „React“ duomenų valdymo nugalėtojai: „Redux“ ir „MobX“, o pastarasis nėra net „Flux“ diegimas. „Redux“ susigaudė tiek, kad nebebuvo naudojama tik „React“. Galite rasti „Redux“ architektūros įgyvendinimus kitoms sistemoms, įskaitant „Angular 2.“. Žr., Pavyzdžiui, „ngrx: store“.

Šoninė pastaba: „MobX“ yra šaunus ir tikriausiai aš jį rinkčiausi per „Redux“ paprastoms naudotojo sąsajoms, nes jis yra mažiau sudėtingas ir mažiau aiškus. Beje, yra keletas svarbių „Redux“ funkcijų, kurių „MobX“ jums nesuteikia, ir prieš nusprendžiant, kas jūsų projektui tinka, svarbu suprasti, kokios jos yra.
Šoninė pastaba: „Relė“ ir „Falcor“ yra kiti įdomūs valstybės valdymo sprendimai, tačiau skirtingai nei „Redux“ ir „MobX“, juos turi paremti atitinkamai „GraphQL“ ir „Falcor Server“, o visos „Relės“ būsenos atitinka tam tikrus serverio duomenis. AFAIK nė viena iš jų nesiūlo geros istorijos, skirtos tik kliento, pereinamojo laikotarpio valstybės valdymui. Galbūt galėsite mėgautis abiejų pusių privalumais sumaišydami ir suderindami „Relay“ arba „Falcor“ su „Redux“ ar „MobX“, išskirdami tik kliento būseną ir nuolatinę serverio būseną. Apatinė eilutė: Šiandien nėra aiškaus kliento valstybės valdymo laimėtojo. Šiam darbui naudokite tinkamą įrankį.

„Redux“ kūrėjas Danas Abramovas surengė keletą puikių kursų šia tema:

  • Darbo su „Redux“ pradžia
  • Programų kūrimas naudojant „Idiomatic Redux“

Abi yra puikios žingsnis po žingsnio vadovėliai, paaiškinantys „Redux“ pagrindus, tačiau norint gauti maksimalią naudą iš „Redux“, jums taip pat reikės aukštesnio lygio supratimo.

Čia pateikiami patarimai, kurie padės sukurti geresnes „Redux“ programas.

1. Supraskite „Redux“ pranašumus

Yra keli svarbūs „Redux“ tikslai, kurių reikia atsiminti:

  1. Deterministinis vaizdas pateikia
  2. Deterministinis valstybės atgaminimas

Nustatant taikymą ir diagnozuojant bei ištaisant klaidas, svarbus yra determinizmas. Jei jūsų programos rodiniai ir būsena yra nedeterministiški, neįmanoma žinoti, ar rodiniai ir būsena visada bus teisingi. Jūs netgi galite pasakyti, kad nedeterminizmas yra savaime klaida.

Tačiau kai kurie dalykai iš esmės nėra nustatomi. Tokie dalykai kaip vartotojo įvesties laikas ir tinklo I / O. Taigi, kaip mes galime žinoti, ar mūsų kodas tikrai veikia? Lengva: izoliacija.

Pagrindinis „Redux“ tikslas yra atskirti valstybės valdymą nuo I / O šalutinių poveikių, tokių kaip vaizdo pateikimas ar darbas su tinklu. Išskyrus šalutinį poveikį, kodas tampa daug paprastesnis. Verslo logiką suprasti ir išbandyti yra daug lengviau, kai ne viskas susipainiojusi su tinklo užklausomis ir DOM atnaujinimais.

Kai rodinio pateikimas yra izoliuotas nuo tinklo įvesties / išvesties ir būsenos atnaujinimų, galite pasiekti deterministinį rodinio pateikimą, reiškiantį: esant tokiai pačiai būsenai, vaizdas visada pateiktų tą pačią išvestį. Tai pašalina tokių problemų, kaip lenktynių sąlygos, galimybę dėl asinchroninių dalykų, atsitiktinai iššluojančių jūsų vaizdo bitus, ar sugadinančių jūsų būsenos bitus, kai jūsų vaizdas yra pateikimo procese.

Naujokas, galvodamas apie rodinio kūrimą, gali pagalvoti: „Šiam bitui reikalingas vartotojo modelis, todėl aš pateiksiu asinchronijos užklausą, kad gautumėte tai, ir kai tas pažadas išsipildys, atnaujinsiu vartotojo komponentą jų vardu. Tam šiek tiek reikia būtinų daiktų, todėl mes juos susigrąžinsime ir, pažadui pasibaigus, mes juos permesime ir patraukime į ekraną “.

Su šiuo metodu susijusios kelios pagrindinės problemos:

  1. Niekada neturite visų duomenų, reikalingų tam, kad bet kuriuo momentu pateiktumėte pilną vaizdą. Jūs faktiškai nepradėjote rinkti duomenų, kol komponentas nepradės daryti savo funkcijų.
  2. Skirtingos iškėlimo užduotys gali būti vykdomos skirtingu metu, subtiliai keičiant tvarką, pagal kurią viskas vyksta rodinio pateikimo seka. Norėdami iš tikrųjų suprasti pateikimo seką, turite žinoti tai, ko negalite numatyti: kiekvieno asinchroninio užklausos trukmę. Pop-testas: kas pirmiau pateikia vartotojo komponentą ar būtinus dalykus? Atsakymas: Tai varžybos!
  3. Kartais įvykių klausytojai mutuoja vaizdo būseną, o tai gali suaktyvinti kitą pateikimą, dar labiau apsunkindama seką.

Pagrindinė problema, kaip išsaugoti duomenis rodinio būsenoje ir suteikti async įvykių klausytojams prieigą mutuoti tą peržiūros būseną, yra ši:

„Nedeterminizmas = lygiagretus apdorojimas + bendroji būsena“
~ Martin Odersky („Scala“ dizaineris)
Duomenų gavimas, manipuliavimas duomenimis ir rūpesčiai dėl vaizdų pateikimo yra laiko keliaujančių spagečių receptas.

Aš žinau, kad tai skamba kietai „B“ filmo moksliniu požiūriu, bet patikėkite manimi, laiko keliaujantys spagečiai yra blogiausio skonio rūšis!

Tai, ką daro srauto architektūra, yra griežtas atskyrimas ir seka, kurie kiekvieną kartą paiso šių taisyklių:

  1. Pirmiausia mes patenkame į žinomą, fiksuotą būseną ...
  2. Tada pateikiame vaizdą. Nieko nebegalės pakeisti šios pateikimo kilpos būsenos.
  3. Atsižvelgiant į tą pačią būseną, vaizdas visada bus pateikiamas vienodai.
  4. Renginių klausytojai klausosi vartotojo įvesties ir tinklo užklausų tvarkytojų. Kai jie juos gauna, veiksmai išsiunčiami į parduotuvę.
  5. Kai veiksmas išsiunčiamas, būsena atnaujinama į naują žinomą būseną ir seka kartojama. Tik išsiųsti veiksmai gali paliesti valstybę.

Trumpai tariant, tai srautas: vienpusė duomenų srauto architektūra jūsų vartotojo sąsajoje:

Flux architektūra

Taikant „Flux“ architektūrą, rodinyje klausomasi vartotojo įvesties, jie paverčiami veiksmo objektais, kurie išsiunčiami į parduotuvę. Parduotuvė atnaujina programos būseną ir praneša vaizdui, kad vėl būtų pateiktas. Žinoma, vaizdas retai yra vienintelis informacijos ir įvykių šaltinis, tačiau tai nėra problema. Papildomi renginių klausytojai išsiunčia veiksmo objektus, kaip ir vaizdas:

Svarbu tai, kad „Flux“ būsenos atnaujinimai yra operatyvūs. Užuot tiesiog paskambinę būsenos atnaujinimo metodu arba tiesiogiai manipuliuojantys reikšme, veiksmo objektai siunčiami į parduotuvę. Veiksmo objektas yra operacijos įrašas. Galite galvoti apie tai kaip apie banko operaciją - atlikto pakeitimo įrašą. Kai atliksite įmoką į savo banką, jūsų likutis prieš 5 minutes nebus sunaikintas. Vietoje to, prie operacijų istorijos pridedamas naujas likutis. Veiksmų objektai prideda operacijų istoriją prie jūsų programos būsenos.

Veiksmo objektai atrodo taip:

Kokius veiksmų objektus jums suteikia, yra galimybė vesti visų valstybės operacijų žurnalą. Šis žurnalas gali būti naudojamas determinuotai atkurti būseną, reiškiančią:

Turėdami tą pačią pradinę būseną ir tas pačias operacijas ta pačia tvarka, visada gausite tą pačią būseną.

Tai turi svarbių pasekmių:

  1. Lengvas išbandymas
  2. Lengvas atšaukimas / perdarymas
  3. Laiko kelionių derinimas
  4. Patvarumas - net jei valstybė sunaikinama, jei turite įrašą apie kiekvieną operaciją, galite ją pakartoti.

Kas nenori įvaldyti erdvės ir laiko? Sandorio būsena suteikia jums laiką keliaujančioms supervalstybėms:

„Redux dev“ įrankių istorijos skaidrių vaizdas

2. Kai kurioms programoms nereikia „Redux“

Jei jūsų vartotojo sąsajos darbo eiga paprasta, visa tai gali būti per didelė. Jei kuriate „tic-tac-toe“ žaidimą, ar tikrai reikia anuliuoti / perdaryti? Žaidimai retai trunka daugiau nei minutę. Jei vartotojas išsisukinėja, galite tiesiog iš naujo nustatyti žaidimą ir leisti jam pradėti iš naujo.

Jei:

  • Vartotojo darbo eigos yra paprastos
  • Naudotojai nebendradarbiauja
  • Jums nereikia valdyti serverio įvykių (SSE) ar internetinių tinklų
  • Duomenys pateikiami iš vieno duomenų šaltinio peržiūros metu

Gali būti, kad įvykių seka programoje tikriausiai yra pakankamai paprasta, kad transakcinės būsenos pranašumai nėra verti papildomų pastangų.

Gal nereikia pataisyti programos. Yra daug paprastesnis sprendimas tokioms programoms. Peržiūrėkite „MobX“.

Tačiau augant jūsų programos sudėtingumui, keičiantis būsenos valdymo sudėtingumui, didėja ir operacijų būsenos vertė, o „MobX“ nepateikia operacijų būsenos valdymo.

Jei:

  • Vartotojo darbo eigos yra sudėtingos
  • Jūsų programoje yra daug įvairių vartotojo darbo eigų (atsižvelkite ir į įprastus vartotojus, ir į administratorius)
  • Vartotojai gali bendradarbiauti
  • Naudojate interneto lizdus arba SSE
  • Įkeliate duomenis iš kelių galinių taškų, kad sukurtumėte vieną vaizdą

Galėtumėte gauti pakankamai naudos iš sandorio valstybės modelio, kad jis būtų vertas pastangų. „Redux“ jums gali tikti.

Ką su tuo turi sąsajos lizdai ir SSE? Kai pridedate daugiau asinchroninio I / O šaltinių, naudojant neapibrėžtą valstybės valdymą tampa sunkiau suprasti, kas vyksta programoje. Deterministinė būsena ir būsenos operacijų įrašas radikaliai supaprastina tokias programas.

Mano nuomone, dauguma didelių „SaaS“ produktų apima bent keletą sudėtingų vartotojo sąsajos darbo eigų ir turėtų naudoti operacijų būsenos valdymą. Daugelio mažų naudingųjų programų ir paprastų prototipų neturėtų būti. Tam darbui naudokite tinkamą įrankį.

3. Suprasti reduktorius

„Redux“ = „Flux“ + funkcinis programavimas

„Flux“ nurodo vienpusį duomenų srautą ir operacijų būseną su veiksmo objektais, tačiau nieko nesako apie tai, kaip tvarkyti veiksmo objektus. Štai kur įeina Redux.

Pagrindinis „Redux“ valstybės valdymo elementas yra reduktoriaus funkcija. Kokia reduktoriaus funkcija?

Funkcinio programavimo metu įprasta naudingumo priemonė „sumažinti ()“ arba „sulankstyti ()“ naudojama reduktoriaus funkcijai kiekvienai reikšmių sąrašo reikšmei, kad būtų sukaupta viena išvesties vertė. Čia pateiktas sumažinimo reduktoriaus, pritaikyto „JavaScript“ masyvui su „Array.prototype.reduce ()“, pavyzdys:

Užuot dirbęs masyvuose, „Redux“ taiko reduktorius veiksmų objektų srautui. Atminkite, kad veiksmo objektas atrodo taip:

Paverskime aukščiau pateiktą sumavimo reduktorių „Redux“ stiliaus reduktoriumi:

Dabar galime jį pritaikyti kai kuriems bandymo veiksmams:

4. Reduktoriai turi būti gryni

Norint pasiekti deterministinį būsenos atkūrimą, reduktoriai turi būti grynos funkcijos. Jokių išimčių. Gryna funkcija:

  1. Naudojant tą pačią įvestį, visada grąžinama ta pati išvestis.
  2. Neturi jokio šalutinio poveikio.

Svarbu „JavaScript“, visi neprimityvūs objektai perduodami funkcijoms kaip nuorodos. Kitaip tariant, jei įvedate objektą, o tada tiesiogiai mutuojate to objekto ypatybę, objektas pasikeičia ir ne pagal funkciją. Tai yra šalutinis poveikis. Jūs negalite žinoti visos funkcijos kvietimo reikšmės, taip pat nežinote visos objekto, kurį praleidote, istorijos. Tai yra blogai.

Vietoj to reduktoriai turėtų grąžinti naują objektą. Tai galite padaryti, pavyzdžiui, naudodamiesi „Object.assign ({}, būsena, {thingToChange})“.

Masyvo parametrai taip pat yra nuorodos. Negalite tiesiog „.push ()“ naujų elementų pateikti į masyvą reduktoriuje, nes „.push ()“ yra mutavimo operacija. Panašiai yra ir „.pop ()“, „.shift ()“, „.unshift ()“, „.reverse ()“, „.splice ()“ ir bet kuris kitas mutavimo būdas.

Jei norite, kad masyvai būtų saugūs, būsenoje atliekamas operacijas turite apsiriboti saugaus prieigos metodais. Vietoj `.push ()` naudokite `.concat ()`.

Pažvelkite į „ADD_CHAT“ atvejį šiame pokalbių reduktoriuje:

Kaip matote, naujas objektas sukuriamas naudojant „Object.assign ()“, o mes pridedame prie masyvo su „.concat ()“, o ne „.push ()“.

Asmeniškai aš nenorėčiau jaudintis dėl netyčinio mano būsenos mutavimo, todėl pastaruoju metu eksperimentuoju su „Redux“ nekeičiamų duomenų API. Jei mano būsena yra nekintantis objektas, man net nereikia žiūrėti kodo, norint žinoti, kad objektas nėra atsitiktinai mutavęs. Prie tokios išvados priėjau dirbdamas komandoje ir atradęs klaidas iš atsitiktinių valstybės mutacijų.

Grynos funkcijos yra daug daugiau nei tai. Jei ketinate naudoti „Redux“ gamybos programoms, jums tikrai reikia gerai suprasti, kas yra grynos funkcijos, ir kitus dalykus, kuriuos reikia atsiminti (pvz., Susijusius su laiku, prisijungimu ir atsitiktiniais skaičiais). Norėdami daugiau sužinoti apie tai, skaitykite skyriuje „Įvaldykite„ JavaScript “interviu: kas yra gryna funkcija?“.

5. Atminkite: reduktoriai turi būti vienintelis tiesos šaltinis

Visoje jūsų programos būsenoje turėtų būti vienas tiesos šaltinis, tai reiškia, kad būsena saugoma vienoje vietoje, o bet kur kitur, kuriai reikalinga būsena, ji turėtų prieiti prie būsenos, remdamasi jos vienu tiesos šaltiniu.

Gerai, kad skirtingiems dalykams yra skirtingi tiesos šaltiniai. Pvz., URL gali būti vienintelis tiesos šaltinis vartotojo užklausos keliui ir URL parametrams. Galbūt jūsų programoje yra konfigūravimo paslauga, kuri yra vienintelis jūsų URL URL tiesos šaltinis. Tai gerai. Tačiau ...

Kai saugote bet kurią valstiją „Redux“ parduotuvėje, prieiga prie šios būsenos turėtų būti suteikta per „Redux“. Nesilaikant šio principo, gali būti pasenę duomenys arba bendrosios būklės mutacijų klaidos, kurias buvo sugalvota išspręsti „Flux“ ir „Redux“.

Kitaip tariant, neturėdami vieno tiesos šaltinio principo, galite prarasti:

  • Deterministinis vaizdo pateikimas
  • Deterministinis būsenos atkūrimas
  • Lengvas atšaukimas / perdarymas
  • Laiko kelionių derinimas
  • Lengvas išbandymas

Arba Redux, arba ne Redux savo valstijoje. Jei padarytumėte tai pusiaukelėje, galėtumėte atsisakyti visų „Redux“ privalumų.

6. Veiksmų tipams naudokite konstantas

Aš norėčiau įsitikinti, kad veiksmus lengva atsekti iki reduktoriaus, kuris juos naudoja, kai žiūrite į veiksmų istoriją. Jei visi jūsų veiksmai turi trumpus, bendrinius pavadinimus, tokius kaip „CHANGE_MESSAGE“, tampa sunkiau suprasti, kas vyksta jūsų programoje. Tačiau jei veiksmų tipai turi daugiau aprašomųjų pavadinimų, tokių kaip „CHAT :: CHANGE_MESSAGE“, tai, aišku, yra daug aiškiau, kas vyksta.

Be to, jei atliksite rašybos klaidą ir išsiųsite nenustatytą veiksmo konstantą, programa išmes klaidą, kad įspėtų apie klaidą. Jei atliksite rašybos klaidą su veiksmo tipo eilute, veiksmas nepavyks tyliai.

Turėdami visus reduktoriaus veiksmų tipus, surinktus vienoje vietoje failo viršuje, taip pat galite padėti:

  • Pavadinimus palaikykite nuosekliai
  • Greitai supraskite reduktoriaus API
  • Peržiūrėkite, kas pasikeitė pateikiant užklausas

7. Norėdami atskirti veiksmo logiką nuo išsiųstų skambintojų, naudokite veiksmo kūrėjus

Kai sakau žmonėms, kad jie negali generuoti ID ar sugriebti esamo laiko reduktoriuje, man atrodo juokinga išvaizda. Jei dabar įtartinai žiūrite į ekraną, būkite tikri: nesate vienas.

Taigi kur yra tinkama vieta tvarkyti nešvarią logiką, nekartojant jos visur, kur reikia naudoti veiksmą? Veiksmo kūrėju.

Veiksmo kūrėjai turi ir kitų privalumų:

  • Laikykite veiksmo tipo konstantas, įtrauktas į reduktoriaus failą, kad nereikėtų jų importuoti niekur kitur.
  • Prieš atlikdami veiksmą, atlikite keletą įvesties skaičiavimų.
  • Sumažinkite katilinę

Panaudosime veiksmo kūrėją, kad būtų sugeneruotas „ADD_CHAT“ veiksmo objektas:

Kaip matote aukščiau, mes naudojame kuidą, kad sugeneruotume atsitiktinius ID kiekvienam pokalbio pranešimui, ir „Date.now ()“, kad sugeneruotume laiko antspaudą. Abi jos yra nešvarios operacijos, kurias saugu vykdyti reduktoriuje, tačiau jas atlikti veiksmo kūrėjams yra visiškai gerai.

Sumažinkite katilo plokštę su veiksmo kūrėjais

Kai kurie žmonės mano, kad veiksmo kūrėjų panaudojimas prideda projektą. Priešingai, jūs ketinate pamatyti, kaip aš juos naudoju, kad smarkiai sumažinčiau katilinę mano reduktoriuose.

Patarimas: jei visas savo konstantas, reduktorius ir veiksmo kūrėjus kaupsite tame pačiame faile, importuodami juos iš atskirų vietų, sumažinsite reikalingą katilo plokštelę.

Įsivaizduokite, kad norime įtraukti galimybę pokalbio vartotojui pritaikyti savo vartotojo vardą ir prieinamumo būseną. Prie reduktoriaus galėtume pridėti keletą veiksmo tipo tvarkytuvų:

Didesniems reduktoriams tai gali išaugti iki daugybės katilų. Daugybė mano sukurtų reduktorių gali būti kur kas sudėtingesni, turint daug nereikalingo kodo. O kas, jei galėtume kartu sutraukti visus paprastus nuosavybės keitimo veiksmus?

Pasirodo, tai nesunku:

Net su papildomais tarpais ir papildomu komentaru ši versija yra trumpesnė - ir tai tik du atvejai. Sutaupytos lėšos tikrai gali susidėti.

Ar ne perjungti ... atvejis pavojingas? Aš matau griūtį!

Galbūt kažkur perskaitėte, kad reikėtų vengti „perjungimo“ teiginių, ypač tam, kad išvengtume atsitiktinio kritimo ir dėl to, kad atvejų sąrašas gali išsipūsti. Galbūt girdėjote, kad niekada neturėtumėte naudoti tyčinio kritimo, nes sunku sugauti atsitiktinius kritimo atvejus. Tai yra geras patarimas, tačiau gerai pagalvokime apie aukščiau minėtus pavojus:

  • Reduktoriai yra kompostuojami, todėl dėmių išsipūtimas nėra problema. Jei jūsų atvejų sąrašas tampa per didelis, suskaidykite gabaliukus ir perkelkite juos į atskirus reduktorius.
  • Kiekvienu atveju kūnas grįžta, todėl atsitiktinis kritimas niekada neturėtų įvykti. Nė vienas sugrupuotas atvejis neturėtų turėti kitų kūnų nei tas, kuris atlieka sugavimą.

„Redux“ gerai naudoja „switch..case“. Aš oficialiai keičiu savo patarimus šiuo klausimu. Kol laikysitės paprastų aukščiau pateiktų taisyklių (laikykite jungiklius mažus ir susikaupusius, o kiekvienu atveju grįžkite su savo kūnu), „jungiklio“ teiginiai yra puikūs.

Galbūt pastebėjote, kad šiai versijai reikalingas kitoks naudingas krovinys. Čia atvyksta jūsų veiksmo kūrėjai:

Kaip matote, šie veiksmo kūrėjai verčia argumentus ir būseną. Bet tai dar ne viskas, ką jie daro ...

8. Parašo dokumentavimui naudokite ES6 parametrų numatytuosius parametrus

Jei naudojate „Tern.js“ su redaktoriaus papildiniu (prieinamas populiariems redaktoriams, tokiems kaip „Sublime Text“ ir „Atom“), jis perskaitys tas ES6 numatytąsias užduotis ir nustatys reikiamą jūsų veiksmų kūrėjų sąsają, taigi, kai jums skambinate, galite gauti automatiškai užpildytą funkciją. Dėl to kūrėjams nebereikia pažinimo, nes jiems nereikės atsiminti reikiamo krovinio tipo ar patikrinti šaltinio kodo, kai pamiršite.

Jei nenaudojate tipo išvados papildinio, pvz., „Tern“, „TypeScript“ ar „Flow“, turėtumėte būti.

Pastaba: Aš mieliau pasikliauju išvadomis, kurias suteikia numatytosios užduotys, matomos funkcijos parašuje, o ne tipo anotacijose, nes:

  1. Nereikia naudoti srauto ar „TypeScript“, kad jis veiktų: vietoj to naudojate standartinį „JavaScript“.
  2. Jei naudojate „TypeScript“ arba „Flow“, komentarai yra nereikalingi pagal numatytuosius priskyrimus, nes ir „TypeScript“, ir „Flow“ nustato tipą iš numatytosios priskyrimo.
  3. Manau, kad ji yra lengviau skaitoma, kai yra mažiau sintaksės triukšmo.
  4. Gaunate numatytuosius nustatymus, o tai reiškia, kad net nesustabdydami CI tipų klaidų (nustebtumėte, daugelis projektų to nedarys), niekada neturėsite atsitiktinio „neapibrėžto“ parametro. kodas.

9. Naudokite parinkiklius apskaičiuotai būsenai ir atsiejimui

Įsivaizduokite, kad kuriate sudėtingiausią pokalbių programą pokalbių programų istorijoje. Parašėte 500 tūkst. Kodo eilučių, ir tada produktų komanda jums iškėlė naują reikalavimą dėl funkcijos, kuri privers jus pakeisti jūsų būsenos duomenų struktūrą.

Nereikia panikuoti. Buvote pakankamai protingi, kad likusią programą atskirtumėte nuo savo būsenos formos pasirinkikliais. Kulka: vengta.

Beveik kiekvienam reduktoriui, kurį rašau, aš sukuriu selektorių, kuris paprasčiausiai eksportuoja visus kintamuosius, kurių man reikia vaizdui sukurti. Pažiūrėkime, kaip tai gali atrodyti paprastam pokalbių reduktoriui:

export const getViewState = state => state;

Taip, aš žinau. Tai taip paprasta, net neverta apie tai atsiminti. Galbūt manote, kad dabar esu pamišęs, bet atsimenate tą kulką, kurios mes vengėme anksčiau? O kas, jei norėtume pridėti apskaičiuotą būseną, pavyzdžiui, išsamų visų vartotojų, kalbėjusių per šią sesiją, sąrašą? Pavadinkime tai „nesenai aktyviais vartotojais“.

Ši informacija jau saugoma dabartinėje būsenoje, bet ne lengvai suprantama. Leiskite eiti į priekį ir paimti jį į „getViewState ()“:

Jei sudėsite visą apskaičiuotą būseną į selektorius, jūs:

  1. Sumažinkite reduktorių ir komponentų sudėtingumą
  2. Atjunkite likusią programos dalį nuo savo valstybinės formos
  3. Laikykitės vieno tiesos šaltinio principo, net savo reduktoriuje

10. Naudokite TDD: pirmiausia parašykite testus

Daugybė tyrimų palygino pirmąjį bandymą su bandymu po metodikų, o bandymų nebuvo atlikta. Rezultatai aiškūs ir dramatiški: Daugelis tyrimų rodo, kad klaidų siuntimo klaidų sumažėjimas 40–80% sumažėjo dėl rašymo testų prieš diegiant funkcijas.

TDD gali efektyviai sumažinti jūsų siuntos klaidų tankį per pusę, ir šiam teiginiui pagrįsti yra daugybė įrodymų.

Rašydamas šio straipsnio pavyzdžius, visus juos pradėjau nuo vienetų testų.

Kad išvengčiau trapių bandymų, aš sukūriau šias gamyklas, kurias naudodama pateikiau lūkesčius:

Atminkite, kad abu šie parametrai suteikia numatytąsias vertes, tai reiškia, kad galiu atskirai ignoruoti ypatybes, kad galėčiau sukurti tik tuos duomenis, kurie mane domina tam tikru testu.

Štai kaip juos panaudojau:

Pastaba: dėl paprastumo aš naudoju juostą vienetų bandymams. Aš taip pat turiu 2–3 metų patirtį su „Mocha“ ir „Jasmine“ bei įvairią patirtį su daugybe kitų struktūrų. Jūs turėtumėte mokėti pritaikyti šiuos principus prie bet kurios pasirinktos sistemos.

Atkreipkite dėmesį į mano sukurtą stilių apibūdinti įdėtus testus. Tikriausiai dėl to, kad turiu „Jasmine“ ir „Mocha“ patirtį, norėčiau pradėti apibūdindamas komponentą, kurį išbandau, išoriniame bloke, o tada vidiniame bloke - apibūdinti tai, ką aš perduodu komponentui. Viduje pateikiu paprastus ekvivalentiškumo tvirtinimus, kuriuos galite padaryti naudodamiesi savo testavimo bibliotekos funkcijomis „deepEqual ()“ arba „toEqual ()“.

Kaip matote, aš naudoju izoliuotą testo būseną ir gamyklos funkcijas, o ne komunalines paslaugas, tokias kaip „beforeEach ()“ ir „afterEach ()“, kurių aš vengiu, nes jos gali paskatinti nepatyrusius kūrėjus naudoti bendrąją būseną bandymų komplekte (tai blogai) .

Kaip jūs tikriausiai atspėjote, aš turiu trijų skirtingų rūšių testus kiekvienam reduktoriui:

  1. Tiesioginiai reduktoriaus testai, kuriuos ką tik matėte. Tai iš esmės patikrina, ar reduktorius sukuria numatytą numatytąją būseną.
  2. Veiksmo kūrėjo testai, kurie išbando kiekvieną veiksmo kūrėją, pritaikant reduktorių veiksmui, kaip atskaitos tašką naudojant iš anksto nustatytą būseną.
  3. Selektorių testai, kuriais tikrinami selektoriai, siekiant įsitikinti, kad yra visos numatomos savybės, įskaitant apskaičiuotas savybes su numatomomis vertėmis.

Jūs jau matėte reduktoriaus testą. Pažvelkime į keletą kitų pavyzdžių.

Veiksmo kūrėjo testai

Šis pavyzdys yra įdomus dėl kelių priežasčių. Veiksmų „addChat ()“ kūrėjas nėra grynas. Tai reiškia, kad jei neįvardinsite vertės viršijimo, negalėsite konkrečiai tikėtis visų pagamintų savybių. Norėdami tai išspręsti, mes panaudojome vamzdį, kurį kartais naudoju, kad išvengčiau papildomų kintamųjų, kurių man tikrai nereikia. Aš jį panaudojau ignoruodamas sugeneruotas vertes. Mes vis dar įsitikiname, kad jie egzistuoja, bet mums nerūpi, kokios yra vertybės. Atminkite, kad net netikrinu tipo. Mes pasitikime rūšies išvada ir numatytosiomis vertėmis, kad tuo pasirūpinsime.

Vamzdis yra funkcinė priemonė, leidžianti perkelti tam tikrą įvesties vertę per keletą funkcijų, kurių kiekviena paima ankstesnės funkcijos išvestį ir tam tikru būdu ją transformuoja. Aš naudoju „lodash pipe“ iš „lodash / fp / pipe“, kuris yra „lodash / flow“ slapyvardis. Įdomu tai, kad pati „pipe ()“ gali būti sukurta su reduktoriaus funkcija:

Aš linkęs daug naudoti „pipe ()“ reduktoriaus failuose, taip supaprastindamas būsenų perėjimus. Visi būsenų perėjimai galiausiai yra duomenų srautai, judantys nuo vieno duomenų pateikimo prie kito. Štai kas yra „pipe ()“.

Atminkite, kad veiksmo kūrėjas taip pat leidžia mums nepaisyti visų numatytųjų verčių, todėl galime perduoti konkrečius ID ir laiko ženklus bei išbandyti konkrečias reikšmes.

Atrankos testai

Galiausiai išbandome būsenos parinkiklius ir įsitikiname, kad apskaičiuotos vertės yra teisingos ir ar viskas yra taip, kaip turi būti:

Atminkite, kad šiame bandyme mes panaudojome „Array.prototype.reduce ()“, kad sumažintume kelis „addChat ()“ pavyzdžių pavyzdžius. Vienas iš nuostabių „Redux“ reduktorių dalykų yra tas, kad jie yra tik įprastos reduktoriaus funkcijos, tai reiškia, kad su jais galite padaryti bet ką, ką darytumėte su kitomis reduktoriaus funkcijomis.

Mūsų „laukiama“ vertė tikrina, ar visi mūsų pokalbių objektai yra žurnale ir ar teisingai išvardyti pastaruoju metu aktyvūs vartotojai.

Nelabai ką kita pasakyti apie tai.

„Redux“ taisyklės

Jei teisingai naudosite „Redux“, gausite didelę naudą:

  • Pašalinkite laiko priklausomybės klaidas
  • Įgalinti deterministinius rodinių pateikimus
  • Įgalinti determinuotą būsenos atkūrimą
  • Įgalinkite paprastas anuliavimo / perdarymo funkcijas
  • Supaprastinkite derinimo procesą
  • Tapk keliautoju

Bet, jei norite, kad viskas veiktų, turite atsiminti keletą taisyklių:

  • Reduktoriai turi būti tik funkcijos
  • Reduktoriai turi būti vienintelis tiesos šaltinis jų būklei
  • Reduktoriaus būsena visada turėtų būti keičiama
  • Reduktoriaus būsenoje neturėtų būti funkcijų

Taip pat atminkite:

  • Kai kurioms programoms nereikia „Redux“
  • Veiksmų tipams naudokite konstantas
  • Naudokite veiksmo kūrėjus, kad atskirtumėte veiksmų logiką nuo išsiuntimo skambinančiųjų
  • Norėdami aprašyti parašus, naudokite ES6 parametrų numatytuosius nustatymus
  • Naudokite parinkiklius apskaičiuotai būsenai ir atsiejimui
  • Visada naudokite TDD!

Mėgautis!

Ar esate pasirengęs išlyginti savo „Redux“ įgūdžius naudodamiesi „DevAnywhere“?

Išmokite patobulintą funkcinį programavimą, „React“ ir „Redux“ patarimus 1: 1. „Lifetime Access“ nariai, patikrinkite funkcinį programavimą ir „Redux“ pamokas. Kai kuriu tikras programas su „React“ ir „Redux“, būtinai žiūrėkite „Shotgun“ seriją ir važinėkite su savimi.

https://devanywhere.io/

Erikas Elliotas yra „Programavimo JavaScript programų“ („O'Reilly“) autorius ir „DevAnywhere.io“ įkūrėjas. Jis prisidėjo prie programinės įrangos patirties „Adobe Systems“, „Zumba Fitness“, „The Wall Street Journal“, ESPN, BBC ir geriausių įrašų atlikėjų, įskaitant Usherį, Franką Okeaną, „Metallica“ ir daugelį kitų.

Jis dirba kur nori, su gražiausia moterimi pasaulyje.