Arhitectura aplicației în elm

Acest ghid descrie arhitectura generală pe care o veți găsi în toate aplicațiile de pe Elm. de la TodoMVC la visător.

Vom studia o modalitate foarte simplă de a conecta o aplicație, care este un bloc infinit imbricat. Ea îmbunătățește foarte mult modularitatea, simplifică reutilizarea codului și testarea. Cu ajutorul acestuia puteți crea aplicații complexe, permițându-le să le comprime în componente. Vom începe cu un mic exemplu și vom extinde treptat, folosind aceste principii de bază.







Interesant, o astfel de arhitectură apare în Elm într-un mod natural. Designul limbii însuși vă aduce la el, indiferent dacă citiți acest text sau nu. Eu am gasit acest model pur si simplu folosind Elm si am fost socat de simplitatea si puterea lui.

Notă. Pentru a încerca codul aici, trebuie să instalați Elm și să fortificați depozitul. Fiecare exemplu are instrucțiuni despre modul de rulare a codului.

Recepție de bază

Logica fiecărui program din Elm este împărțită în trei părți clar separate: model, actualizare și afișare. Puteți începe de fiecare dată cu acest proiect de schelet și apoi completați-l treptat cu detalii pentru sarcina dvs. specifică.

Întregul tutorial vom folosi acest model cu mici modificări și completări.

Exemplu # 1: Counter

Codul începe cu un model foarte simplu. Trebuie doar să urmărim un număr:

Când actualizați modelul, este, de asemenea, foarte simplu. Definim un set de acțiuni care pot fi efectuate și se adaugă prelucrarea lor la funcția de actualizare:

Acum rămâne doar să facem un afiș pentru modelul nostru. Vom folosi elm-html pentru a crea HTML, care va fi afișat în browser. Creăm un div. care conține: un buton de scădere, un div cu valoarea curentă a contorului și un buton de creștere.

Partea cea mai dificilă a funcției de vizualizare este Signal.Address. Vom face acest lucru în următoarea parte, dar pentru moment vreau să remarcați că acest cod este complet declarativ. Luăm modelul și oferim câteva html-uri. Și asta e tot. În nici un caz nu facem schimbarea DOM manuală, care deschide biblioteca mult spațiu pentru optimizare și chiar accelerează foarte mult totul. Este minunat. Mai mult decât atât, funcția de vizualizare este cea mai obișnuită funcție și la crearea ei putem folosi întreaga putere a sistemului modulului Elm, a cadrelor de testare și a bibliotecilor.

Aceasta este esența aspectului oricărei aplicații din Elm. Toate exemplele pe care le vom vedea mai jos sunt doar mici variații ale acestui model îndrăzneț: modelul, actualizarea, vizualizarea.

Retreat: Revitalizarea aplicației dvs. cu semnale

Acum, să aruncăm o privire asupra părții codului cu Signal.Address.

Înainte de aceasta, am vorbit doar despre funcții pure și date imuabile. Este minunat, dar trebuie să reacționăm și la evenimente din lumea exterioară. În Elm, sunt implicate semnale. Un semnal este o valoare care se schimbă odată cu timpul, ceea ce ne permite să vorbim despre modul în care modelul nostru se va schimba.

În principiu, toate programele vor avea această mică bucată de cod care servește întregii aplicații. În exemplul 1, se arată astfel:

Vreau să vă atrag atenția asupra câtorva detalii:

  1. Începem cu valoarea 0 ca valoare de pornire a modelului.
  2. Folosim funcția de actualizare pentru a avansa starea modelului.
  3. Răspundem la acțiunile (acțiune) care vin în canal.
  4. Afișăm toate acestea pe ecran prin intermediul funcției de vizualizare.

În loc să încercați imediat să înțelegeți ce se întâmplă pe fiecare linie, vă sugerăm mai întâi să priviți schema a ceea ce se întâmplă la un nivel înalt.

Partea albastră este programul nostru, adică exact modelul / actualizarea / afișarea despre care am vorbit. De cele mai multe ori puteți lucra fără a lăsa limitele acestui domeniu.

Nou aici sunt "canalele" și modul în care acestea permit noilor acțiuni (acțiune) să apară ca răspuns la intrarea utilizatorului. În imagine, acestea sunt reprezentate de liniile punctate de pe monitor în programul dvs. Când atribuim anumite canale funcției de vizualizare. determinăm modul în care acțiunile utilizatorului se vor potrivi în codul nostru. Rețineți că nu efectuăm aceste acțiuni, ci pur și simplu le înregistrați pentru programul nostru principal. Această separare este o caracteristică cheie!

Vreau să notez că acest cod cu Signal este la fel pentru toate programele din Elm. Poate doriți să aflați mai multe despre semnale. dar pentru a continua să citiți, veți avea destule din această înțelegere comună. Vrem să descriem arhitectura și să nu ne împotmolim în felul în care funcționează totul. Deci, să mergem la extinderea exemplului nostru!







Exemplu # 2: O pereche de contoare

În primul exemplu, am creat un contor simplu, dar cum va fi aceasta scalată atunci când avem nevoie de două contoare? Putem păstra modularitatea?

Principala noastră sarcină acum este de a reutiliza întregul cod al exemplului anterior. Pentru a realiza acest lucru, vom crea un modul independent Counter. în care am pus toate detaliile implementării contorului. Singura modificare este în funcția de vizualizare. așa că nu voi dezvălui toate definițiile vechi.

Acum că avem modulul de bază Counter. să creăm aplicația CounterPair. Ca întotdeauna, începem cu modelul:

Modelul nostru este un record cu două câmpuri, unul pentru fiecare contor pe care dorim să-l afișăm pe ecran. Aceasta reflectă pe deplin starea aplicației. De asemenea, avem funcția init. creând un nou model atunci când avem nevoie de el.

Apoi, definim setul de acțiuni pe care dorim să le sprijinim. De data aceasta vom avea: resetați toate contoarele, actualizați contorul superior sau actualizați contorul inferior.

Rețineți că tipul nostru de conectare indică tipul Counter.Action. dar nu știm subtilitatea acestor acțiuni. Atunci când creăm funcția de actualizare, trimitem pur și simplu aceste acțiuni la locul potrivit:

Și în cele din urmă rămâne doar să se facă funcția de afișare, care va afișa atât contorul nostru, cât și butonul de resetare de pe ecran.

Exemplul # 3: Lista dinamică a contoarelor

Câteva contoare sunt minunate, dar o listă de contoare, la care poți adăuga altele noi și le șterge la cerere? Recepția noastră va funcționa aici?

În acest exemplu, vom folosi același modul Counter. ca în exemplul 2.

Aceasta înseamnă că vom trece imediat la modulul CounterList. Ca de obicei, începem cu modelul:

Acum, modelul nostru este o listă de contoare, fiecare cu identitatea sa unică. Acești identificatori ne permit să distingem contoarele și când vrem să actualizăm al patrulea, vom avea o modalitate ușoară de a face acest lucru. (În plus, aceste coduri oferă o modalitate convenabilă de a defini o cheie unică atunci când ne gândim la optimizarea redării componentelor, dar nu vom mai vorbi despre acest subiect acum). În plus, modelul are un câmp următor. Aceasta ne ajută să atribuim identificatori unici când adăugăm contoare noi.

Să descriem un set de acțiuni pe care le putem aplica modelului nostru. Vrem să adăugăm contoare, să le ștergem și să schimbăm și valorile contoarelor individuale.

Acțiunea noastră de asociere de tip este foarte asemănătoare cu comportamentul descris mai sus.

Să descriem funcția de actualizare.

Iată o descriere generală a fiecărui caz:

Insert - Mai întâi vom crea un nou contor și îl vom pune la sfârșitul listei. Apoi, mărim ID-ul următor, astfel încât data viitoare să avem pregătit ID-ul.

Eliminare - Eliminați primul element din lista noastră de contoare.

Modificați - Trecem prin lista contoarelor și, dacă identificatorul dorit este prins, numim Acțiunea pentru acest contor.

Tot ce a mai rămas este funcția de afișare.

Atunci când creăm funcția de vizualizare a unei aplicații, folosim funcția viewCounter pentru fiecare element din listă. Și atunci când creăm butoane de adăugare și ștergere care trimit mesaje direct la canalul de adrese al adresei.

Un truc similar cu ID-ul poate fi folosit oriunde, unde aveți nevoie de o cantitate dinamică de componente imbricate. Contoarele sunt destul de simple, dar acest model va funcționa exact la fel dacă aveți o listă cu profiluri de utilizatori, tweets, articole de știri sau produse de știri.

Exemplu # 4: Listă avansată de contoare

Bine, păstrează lucrurile simple și modulare pentru lista de contoare este mare, dar ce se întâmplă dacă, în loc de butonul de resetare generală fiecare contor va avea un buton de ștergere? Cu siguranta va sparge totul!

Nu, funcționează.

În acest caz, avem nevoie de un nou mod de a crea contoare cu butoanele lor. Putem lăsa funcția de vizualizare veche și doar să adăugăm o nouă vizualizareWithRemoveButton. care va atrage un model ușor diferit. Nu este nevoie să duplicăm codul sau să facem cascadorii nebun cu moștenire sau suprasolicitare. Vom adăuga pur și simplu o nouă funcție la interfața publică a modulului care implementează noua funcție!

Acum, că avem o vedereWithRemoveButton. putem crea un modul CounterList. în care vom strânge împreună toate contoarele. Tipul de model va fi folosit la fel ca în exemplul # 3: o listă de contoare și un număr unic.

Acțiunile posibile vor fi puțin diferite. În loc să ștergem toate contoarele vechi, dorim să ștergem numai cel al cărui cod este identic cu cel specificat.

Funcția de actualizare nu diferă mult de exemplul anterior.

Când apare Eliminare, eliminăm contorul care are ID-ul celui pe care trebuie să îl eliminăm. În rest, totul este la fel.

În cele din urmă, colectăm toate acestea împreună în viziunea:

Noțiuni de bază

Recepție de bază - Totul este construit în jurul tipului de model. actualizați funcția pentru actualizare și afișați funcția de afișare. Mai departe, doar variațiile acestei metode sunt.

Adăugarea contextului - uneori aveți nevoie de informații suplimentare pentru actualizarea sau afișarea modelului. Putem adăuga mereu context la aceste funcții fără a încărca tipul principal de model.

La fiecare nivel de cuibărit, putem defini acest context. care este necesar pentru componentele interne.

Testare ușoară - Toate funcțiile sunt curate. Acest lucru le permite să fie foarte ușor de testat - nu este necesară o inițializare specială sau un mediu artificial, ci doar să le oferiți argumentele pe care doriți să le încercați.

Un alt șablon

Există o altă modalitate importantă de a extinde metoda de bază. De exemplu, este posibil să fie nevoie să actualizați componenta și, în funcție de rezultat, trebuie să schimbați altceva în altă parte a programului. Puteți extinde funcția de actualizare. astfel încât să returneze mai multe informații.

În funcție de actualizarea logică de procesare. putem spune cuiva de mai sus să actualizeze conținutul sau să scoată ceva. În mod similar, o componentă se poate elimina:

Dacă nu este foarte clar cum funcționează aceasta, probabil că voi scrie un exemplu 5 care folosește această tehnică. Între timp, vă puteți uita la exemple similare în versiunea amuzantă a aplicației TodoMVC de pe Elm.







Articole similare

Trimiteți-le prietenilor: