Tere tulemast tagasi teise põneva osa jaoks ClojureScripti maandamine ! Selles postituses käsitlen järgmist suurt sammu ClojureScripti tõsiseks muutmiseks: olekuhaldus - antud juhul Reacti kasutamine.
Eesmise tarkvara abil on riigi haldamine suur asi. Karbist väljas on paar viisi oleku käsitlemiseks Reageeri :
Üldiselt pole kumbki neist tore. Oleku hoidmine tipptasemel on üsna lihtne, kuid siis on rakenduse oleku edastamiseks kõigile komponentidele, mis seda vajavad, palju lisakulusid.
Võrdluseks võib öelda, et globaalsete muutujate (või muude olekute naiivsete versioonide) olemasolu võib põhjustada raskesti jälgitavaid samaaegsusega seotud probleeme, mille tulemusel komponente ei värskendata, kui te neid eeldate, või vastupidi.
Niisiis, kuidas saab sellega toime tulla? Neile, kes tunnevad Reactit, olete proovinud Reduxi, olekukonteinerit JavaScripti rakendused. Võimalik, et olete selle leidnud omal soovil, otsides julgelt juhitavat süsteemi riigi säilitamiseks. Või olete lihtsalt JavaScripti ja muude veebitööriistade kohta lugedes komistanud.
Sõltumata sellest, kuidas inimesed lõpuks Reduxit vaatavad, jõuavad minu kogemuseni tavaliselt kaks mõtet:
Üldiselt pakub Redux abstraktsiooni, mis võimaldab riigi haldusel sobida reaktiivne reageerimise olemus. Allalaadides kogu olekusüsteemi sellisele süsteemile nagu Redux, säilitate puhtus React. Seega on teil palju vähem peavalusid ja üldiselt midagi, mida on palju lihtsam põhjendada.
Ehkki see ei pruugi aidata teil ClojureScripti täiesti nullist õppida, võtan siinkohal vähemalt kokku mõned Clojure [Script] olekute põhimõisted. Kui juba olete, jätke need osad vahele staažikas Clojurian !
Tuletage meelde üks Clojure'i põhitõdedest, mis kehtib ka ClojureScripti kohta: Vaikimisi andmed on muutumatud . See sobib suurepäraselt arendamiseks ja tagatiseks, et ajahetkel N loodu on ajahetkel> N. ikka sama. ClojureScript pakub meile ka atom
kaudu mugavat viisi muutuva oleku saamiseks, kui seda vajame. kontseptsioon.
An atom
ClojureScriptis on väga sarnane tähisega AtomicReference
Java-s: see pakub uue objekti, mis lukustab selle sisu samaaegsuse garantiidega. Nii nagu Java-s, saate ka sellesse objekti paigutada kõik, mis teile meeldib - sellest ajast alates on see aatom aatomi viide sellele, mida soovite.
Kui teil on oma atom
, saate selle aatomina seada uue väärtuse, kasutades reset!
funktsioon (pange tähele funktsiooni !
| Clojure keeles kasutatakse seda sageli operatsiooni olekulisuse või ebapuhasuse tähistamiseks).
Pange tähele ka seda, et erinevalt Java-st pole Clojure hooliv, mida te oma atom
See võib olla string, loend või objekt. Dünaamiline tippimine, kullake!
(def my-mutable-map (atom {})) ; recall that {} means an empty map in Clojure (println @my-mutable-map) ; You 'dereference' an atom using @ ; -> this prints {} (reset! my-mutable-map {:hello 'there'}) ; atomically set the atom (reset! my-mutable-map 'hello, there!') ; don't forget Clojure is dynamic :)
Reaktiiv laiendab seda aatomi mõistet oma atom
(Kui te pole reagendiga tuttav, vaadake lehte postitus enne seda .) See käitub identselt ClojureScripti atom
välja arvatud see, et see käivitab ka Reagendis renderdamissündmused, nagu ka Reacti sisseehitatud olekupood.
Näide:
(ns example (:require [reagent.core :refer [atom]])) ; in this module, atom now refers ; to reagent's atom. (def my-atom (atom 'world!')) (defn component [] [:div [:span 'Hello, ' @my-atom] [:input {:type 'button' :value 'Press Me!' :on-click #(reset! My-atom 'there!')}]])
See näitab ainsust, mis sisaldab öeldes: 'Tere, maailm!' ja nupp, nagu võite arvata. Selle nupu vajutamine muteerib
my-atom
sisaldama 'there!'
. See käivitab komponendi ümberjoonistamise, mille tulemuseks on span „Hello, there!” selle asemel.
See tundub kohaliku komponenditaseme mutatsiooni jaoks piisavalt lihtne, kuid mis siis, kui meil on keerulisem rakendus, millel on mitu abstraktsiooni taset? Või kui peame jagama ühist olekut mitme alamkomponendi ja nende alamkomponendi vahel?
Uurime seda ühe näitega. Siin juurutame toore sisselogimislehe:
(ns unearthing-clojurescript.login (:require [reagent.core :as reagent :refer [atom]])) ;; -- STATE -- (def username (atom nil)) (def password (atom nil)) ;; -- VIEW -- (defn component [on-login] [:div [:b 'Username'] [:input {:type 'text' :value @username :on-change #(reset! username (-> % .-target .-value))}] [:b 'Password'] [:input {:type 'password' :value @password :on-change #(reset! password (-> % .-target .-value))}] [:input {:type 'button' :value 'Login!' :on-click #(on-login @username @password)}]])
Seejärel hostime seda sisselogimiskomponenti oma peamises app.cljs
-is:
(ns unearthing-clojurescript.app (:require [unearthing-clojurescript.login :as login])) ;; -- STATE (def token (atom nil)) ;; -- LOGIC -- (defn- do-login-io [username password] (let [t (complicated-io-login-operation username password)] (reset! token t))) ;; -- VIEW -- (defn component [] [:div [login/component do-login-io]])
Eeldatav töövoog on seega:
do-login-io
funktsioon vanemkomponendis.do-login-io
funktsioon teeb mõningaid sisend- ja väljundoperatsioone (näiteks serverisse sisselogimine ja loa hankimine).Kui see toiming blokeerib, on meil juba palju probleeme, kuna meie rakendus on külmunud - kui see pole nii, siis peame muretsema asünkrooni pärast!
Lisaks peame nüüd pakkuma selle märgi kõigile oma alamkomponentidele, kes soovivad meie serveris päringuid teha. Koodi taastamine läks lihtsalt palju raskemaks!
Lõpuks, meie komponent pole nüüd enam puhtalt reaktiivne —See on nüüd kaasatud ülejäänud rakenduse oleku haldamisse, I / O käivitamisse ja üldiselt veidi häirivaks.
Redux on võlukepp, mis viib kõik teie riigipõhised unistused täide. Korralikult rakendatuna pakub see olekut jagavat abstraktsiooni, mis on turvaline, kiire ja hõlpsasti kasutatav.
Reduxi sisemine töö (ja selle taga olev teooria) jäävad mõnevõrra väljapoole seda artiklit. Selle asemel sukeldun ClojureScripti toimivasse näitesse, mis loodetavasti peaks mingil moel näitama, milleks see võimeline on!
Meie kontekstis rakendab Reduxi üks paljudest saadaval olevatest ClojureScripti teekidest; see helistas ümber kaader . See pakub Cluxi ümbritsetud ümbrist Reduxi ümber, mis (minu arvates) muudab selle kasutamise absoluutseks rõõmuks.
Redux tõstab teie rakenduse oleku välja, jättes komponendid kergeks. Taastatud komponent peab mõtlema ainult sellele:
Amazoni veebiteenuste lahenduste arhitekti sertifikaat
Ülejäänuga tegeletakse kulisside taga.
Selle punkti rõhutamiseks täiendame ülalolevat sisselogimislehte.
Esiteks: peame otsustama, milline meie rakendusmudel välja näeb. Me teeme seda, määratledes kuju meie andmetest, mis on kogu rakenduses juurdepääsetavad.
Hea rusikareegel on see, et kui andmeid tuleb kasutada mitmetes Reduxi komponentides või need peavad olema pikaealised (nagu meie luba on), siis tuleks need andmebaasi salvestada. Seevastu, kui andmed on komponendi kohalikud (näiteks meie kasutajanime ja parooli väljad), peaksid need elama kohaliku komponendi olekuna ja neid ei tohiks andmebaasi salvestada.
Koostame oma andmebaasi katlaplaadi ja täpsustame oma loa:
(ns unearthing-clojurescript.state.db (:require [cljs.spec.alpha :as s] [re-frame.core :as re-frame])) (s/def ::token string?) (s/def ::db (s/keys :opt-un [::token])) (def default-db {:token nil})
Siinkohal väärib märkimist mõned huvitavad punktid:
spec
raamatukogu kuni kirjeldab kuidas meie andmed peaksid välja nägema. See on eriti asjakohane dünaamilises keeles nagu Clojure [Script].:opt-un
märksõna, mis tähistab valikulist, kvalifitseerimata. (Rakenduses Clojure oleks tavaline märksõna umbes selline :cat
, kvalifitseeritud märksõna aga umbes selline :animal/cat
. Kvalifitseerumine toimub tavaliselt mooduli tasemel - see takistab erinevate moodulite märksõnadel üksteist röövimast .)Peaksime igal ajahetkel olema kindlad, et meie andmebaasis olevad andmed vastavad meie spetsifikatsioonidele.
Nüüd, kui oleme oma andmemudeli kirjeldanud, peame kajastama, kuidas meie vaade näitab neid andmeid. Oleme juba kirjeldanud, kuidas meie vaade meie Reduxi komponendis välja näeb - nüüd peame lihtsalt oma vaate oma andmebaasiga ühendama.
Reduxiga ei pääse me oma andmebaasile otse juurde - see võib põhjustada elutsükli ja samaaegsuse probleeme. Selle asemel registreerime oma suhted andmebaasi tahuga läbi tellimusi .
Tellimus ütleb uuesti kaadrile (ja Reagendile), et sõltume andmebaasi osast ja kui seda osa muudetakse, tuleks meie Reduxi komponent uuesti renderdada.
Tellimusi on väga lihtne määratleda:
(ns unearthing-clojurescript.state.subs (:require [re-frame.core :refer [reg-sub]])) (reg-sub :token ; <- the name of the subscription (fn [{:keys [token] :as db} _] ; first argument is the database, second argument is any token)) ; args passed to the subscribe function (not used here)
Siin registreerime ühe loa enda tellimuse. Tellimus on lihtsalt tellimuse nimi ja funktsioon, mis selle üksuse andmebaasist välja võtab. Me võime selle väärtuse jaoks teha kõike, mida tahame, ja muteerida vaadet nii palju kui meile siin meeldib; sellisel juhul võtame märgise lihtsalt andmebaasist välja ja tagastame.
On palju, palju saate tellimustega rohkem teha - näiteks määratleda vaated andmebaasi alamjaotistele, et uuesti renderdamine oleks tihedam - kuid me hoiame selle praegu lihtsana!
Meil on oma andmebaas ja meil on oma vaade andmebaasi. Nüüd peame käivitama mõned sündmused! Selles näites on meil kahte tüüpi üritusi:
Alustame lihtsast. Uuesti kaader pakub isegi täpselt sellise sündmuse jaoks funktsiooni:
(ns unearthing-clojurescript.state.events (:require [re-frame.core :refer [reg-event-db reg-event-fx reg-fx] :as rf] [unearthing-clojurescript.state.db :refer [default-db]])) ; our start up event that initialises the database. ; we'll trigger this in our core.cljs (reg-event-db :initialise-db (fn [_ _] default-db)) ; a simple event that places a token in the database (reg-event-db :store-login (fn [db [_ token]] (assoc db :token token)))
Jällegi on see siin üsna lihtne - oleme määranud kaks sündmust. Esimene on meie andmebaasi lähtestamiseks. (Vaadake, kuidas see ignoreerib mõlemaid tema argumente? Initsialiseerime andmebaasi alati meie default-db
! -Ga!) Teine on meie loa salvestamiseks, kui oleme selle saanud.
Pange tähele, et kummalgi neist sündmustest pole kõrvaltoimeid - pole väliskõnesid, pole üldse I / O-sid! See on püha Reduxi protsessi pühaduse säilitamiseks väga oluline. Ärge tehke seda ebapuhta, et te ei sooviks endale Reduxi viha.
Lõpuks vajame oma sisselogimisüritust. Asetame selle teiste alla:
(reg-event-fx :login (fn [{:keys [db]} [_ credentials]] {:request-token credentials})) (reg-fx :request-token (fn [{:keys [username password]}] (let [token (complicated-io-login-operation username password)] (rf/dispatch [:store-login token]))))
reg-event-fx
funktsioon on suures osas sarnane reg-event-db
-ga, ehkki on mõningaid peent erinevusi.
reg-event-db
db
tagastada, tagastame selle asemel kaardi, mis näitab kõiki efekte ('fx'), mis peaksid selle sündmuse jaoks juhtuma. Sellisel juhul helistame lihtsalt :request-token
mõju, mis on määratletud allpool. Üks muudest kehtivatest mõjudest on :dispatch
, mis kutsub lihtsalt teist sündmust.Kui meie mõju on saadetud, on meie :request-token
kutsutakse efekti, mis teeb meie pikaajalise sisend- / väljundlogimise. Kui see on lõpule jõudnud, saadab see õnnelikult sündmuse tagasi, lõpetades nii tsükli!
Niisiis! Oleme määratlenud oma ladustamise abstraktsiooni. Kuidas komponent praegu välja näeb?
(ns unearthing-clojurescript.login (:require [reagent.core :as reagent :refer [atom]] [re-frame.core :as rf])) ;; -- STATE -- (def username (atom nil)) (def password (atom nil)) ;; -- VIEW -- (defn component [] [:div [:b 'Username'] [:input {:type 'text' :value @username :on-change #(reset! username (-> % .-target .-value))}] [:b 'Password'] [:input {:type 'password' :value @password :on-change #(reset! password (-> % .-target .-value))}] [:input {:type 'button' :value 'Login!' :on-click #(rf/dispatch [:login {:username @username :password @password]})}]])
Ja meie rakenduse komponent:
(ns unearthing-clojurescript.app (:require [unearthing-clojurescript.login :as login])) ;; -- VIEW -- (defn component [] [:div [login/component]])
Ja lõpuks on mõnes kaugkomponendis meie märgile juurdepääsemine sama lihtne kui:
(let [token @(rf/subscribe [:token])] ; ... )
Kõike kokku panema:
rahavoogude aruanne bilansist ja kasumiaruandest
Pole jalgu, ei pea.
Reduxi (re-frame kaudu) lahutasime vaate komponendid edukalt oleku käitlemise segadusest. Meie riikliku abstraktsiooni laiendamine on nüüd käkitegu!
Redux ClojureScriptis tõesti on nii lihtne - teil pole vabandust seda proovimata jätta.
Kui olete valmis pragunema, soovitaksin seda vaadata fantastiline uuesti raamida dokumente ja meie lihtne töötanud näide . Ootan teie kommentaare selle ClojureScripti õpetuse kohta allpool. Palju edu!
Seotud: Riigi haldamine nurkades Firebase'i abilReduxi olek viitab ühele poodile, mida Redux kasutab rakenduse oleku haldamiseks. Seda poodi kontrollib ainuüksi Redux ja sellele ei pääse otse rakendusest.
Ei, Redux on eraldiseisev muster, mida nimetatakse sündmuste hankimiseks. Redux sai inspiratsiooni teisest tehnoloogiast nimega Flux.
Reduxi konteiner (või lihtsalt 'konteiner') on Reaxti komponent, mis tellib Reduxi oleku ja saab värskendusi, kui oleku see osa muutub.
Jah, Redux pakub veebirakenduses raamistiku riigi halduse ümber.
ClojureScript on Clojure'i kompilaator, mis sihib JavaScripti. Seda kasutatakse tavaliselt veebirakenduste ja teekide ehitamiseks Clojure keelt kasutades.