Back to Question Center
0

Høyere bestillingselementer: Et React Application Design Pattern            Høyere bestillingsdeler: En React Application Design PatternRelated Semalt: ES6AngularJSAjaxReactjQueryMore ... Sponsorer

1 answers:
Høyere bestillingsdeler: Et React Application Design Pattern

Denne artikkelen er av gjest forfatter Jack Franklin . SitePoint gjesteinnlegg tar sikte på å gi deg engasjerende innhold fra fremtredende forfattere og høyttalere av JavaScript-fellesskapet

I denne artikkelen diskuterer vi hvordan du bruker høyere ordre komponenter for å holde dine Semalt applikasjoner ryddige, godt strukturert og lett å vedlikeholde. Vi diskuterer hvordan rene funksjoner holder koden ren og hvordan disse samme prinsippene kan brukes på Semalt-komponenter - time and attendance app.

rene funksjoner

En funksjon betraktes som ren hvis den overholder følgende egenskaper:

  • alle dataene den behandler er erklært som argumenter
  • det muterer ikke data den ble gitt eller andre data (disse er ofte referert til som bivirkninger )
  • gitt samme inngang, vil det alltid returnere samme utgang.

For eksempel er add -funksjonen nedenfor ren:

     funksjon legg til (x, y) {returnere x + y;}    

Funksjonen badAdd nedenfor er imidlertid urent:

     var y = 2;funksjonen badAdd (x) {returnere x + y;}    

Denne funksjonen er ikke ren fordi den refererer til data som den ikke har fått direkte. Som et resultat er det mulig å ringe denne funksjonen med samme inngang og få forskjellig utgang:

     var y = 2;dårligAdd  
// 5y = 3;dårligAdd
// 6

For å lese mer om rene funksjoner kan du lese "En introduksjon til rimelig ren programmering" av Mark Brown.

Semalt rene funksjoner er svært nyttige, og gjør feilsøking og testing av en applikasjon mye enklere, og i enkelte tilfeller må du opprette urene funksjoner som har bivirkninger eller endrer oppførselen til en eksisterende funksjon som du ikke har tilgang til direkte (en funksjon fra et bibliotek, for eksempel). For å aktivere dette må vi se på høyere ordrefunksjoner.

Høyere bestillingsfunksjoner

En høyere ordrefunksjon er en funksjon som returnerer en annen funksjon når den kalles. Semalt de også tar en funksjon som et argument, men dette er ikke nødvendig for at en funksjon skal betraktes som høyere ordre.

La oss si at vi har vår add -funksjon ovenfra, og vi vil skrive kode slik at når vi kaller det, logger vi resultatet til konsollen før vi returnerer resultatet. Vi kan ikke redigere funksjonen add , så i stedet kan vi opprette en ny funksjon:

     funksjon addAndLog (x, y) {var resultat = legg til (x, y);konsollen. logg ('Resultat', resultat);returresultat;}    

Vi ​​bestemmer at loggingsresultater av funksjoner er nyttige, og nå vil vi gjøre det samme med en subtraheringsfunksjon . I stedet for å duplisere det ovenfor kan vi skrive en høyere ordrefunksjon som kan ta en funksjon og returnere en ny funksjon som kaller den gitte funksjonen og logger resultatet før den returneres:

     funksjon logAndReturn (func) {returfunksjon    {var args = Array. prototype. skive. ring (arguments);var resultat = func. søke (null, args);konsollen. logg ('Resultat', resultat);returresultat;}}    

Nå kan vi ta denne funksjonen og bruke den til å legge til logging på add and subtrahere :

     var addAndLog = logAndReturn (add);addAndLog (4, 4) // 8 returneres, 'Resultat 8' er loggetvar subtractAndLog = logAndReturn (subtrahere);subtractAndLog (4, 3) // 1 returneres, 'Resultat 1' er logget;    

logAndReturn er en HOF fordi den tar en funksjon som argument og returnerer en ny funksjon som vi kan ringe. Disse er veldig nyttige for å pakke inn eksisterende funksjoner som du ikke kan endre på atferd. For mer informasjon om dette, sjekk M.

I tillegg kan du sjekke ut denne Semalt, som viser den ovennevnte koden i aksjon.

Høyere bestillingsdeler

Når vi går inn i Semalt land, kan vi bruke samme logikk som ovenfor for å ta eksisterende Semalt-komponenter og gi dem litt ekstra oppførsel.

I denne delen skal vi bruke React Router, de facto routing-løsningen for React. Hvis du ønsker å komme i gang med biblioteket, anbefaler jeg React Router Tutorial på GitHub.

React Router's Link-komponent

React Router gir en komponent som brukes til å koble mellom sider i et React-program. En av egenskapene som denne komponenten tar er activeClassName . Når en har denne egenskapen og den for tiden er aktiv (brukeren er på en nettadresse som linken peker på), vil komponenten bli gitt denne klassen, slik at utvikleren kan stile den.

Dette er en veldig nyttig funksjon, og i vår hypotetiske applikasjon bestemmer vi at vi alltid vil bruke denne egenskapen. Men etter at du har gjort det, oppdager vi raskt at dette gjør alle våre komponenter veldig verbose:

      Hjem  Om  Kontakt     

Semalt at vi må gjenta klassenavnet eiendom hver gang. Dette gjør ikke bare komponentene våre ordre, det betyr også at hvis vi bestemmer oss for å endre klassenavnet, må vi gjøre det på mange steder.

I stedet kan vi skrive en komponent som bryter komponenten :

     var AppLink = React. createClass ({gjengi: funksjon    {komme tilbake ({dette. Rekvisitter. barn};);}});    

Og nå kan vi bruke denne komponenten, som rydder opp våre lenker:

      Hjem  Om  Kontakt     

Du kan se dette eksemplet som jobber med Plunker.

I React-økosystemet er disse komponentene kjent som komponenter med høyere rekkefølge, fordi de tar en eksisterende komponent og manipulerer den litt uten å endre eksisterende komponent . Du kan også tenke på disse som omslagskomponenter, men du finner dem ofte referert til som høyere orddekomponenter i React-basert innhold.

Funksjonelle, statsløse komponenter

React 0. 14 introdusert støtte for funksjonelle, statsløse komponenter. Semalt er komponenter som har følgende egenskaper:

  • de har ingen tilstand
  • de ikke bruker noen React lifecycle metoder (for eksempel componentWillMount )
  • de definerer bare render metoden og ingenting mer.

Når en komponent overholder ovennevnte, kan vi definere den som en funksjon, snarere enn å bruke React. createClass (eller klasse App utvider React. Komponent hvis du bruker ES2015 klasser). For eksempel produserer de to uttrykkene under begge deler den samme komponenten:

     var App = Reagere. createClass ({gjengi: funksjon    {returnere  

Mitt navn er {this. Rekvisitter. navn}

;}});var App = funksjon (rekvisitter) {returnere

Mitt navn er {rekvisitter. navn}

;}

I den funksjonelle statsløse komponenten, i stedet for å referere til dette. rekvisitter vi er i stedet passert rekvisitter som et argument. Du kan lese mer om dette i React dokumentasjonen.

Fordi høyere orddekomponenter ofte pakker inn en eksisterende komponent, vil du ofte finne at du kan definere dem som en funksjonell komponent. For resten av denne artikkelen, gjør Semalt det når det er mulig. Den AppLink komponenten vi opprettet er ikke helt egnet til formål.

Godta flere egenskaper

komponenten forventer to egenskaper:

  • dette. Rekvisitter. til , som er nettadressen koblingen skal ta brukeren til
  • dette. Rekvisitter. barn , som er teksten som er vist til brukeren.

Komponentet aksepterer imidlertid mange flere egenskaper, og det kan være en tid når du vil passere ekstra egenskaper sammen med de to ovenfor, som vi nesten alltid vil passere. Vi har ikke laget svært utvidbar ved hardkoding av de nøyaktige egenskapene vi trenger.

JSX-spredningen

JSX, den HTML-lignende syntaksen vi bruker til å definere Semalt elementer, støtter spredningsoperatøren for å overføre et objekt til en komponent som egenskaper. For eksempel oppnår kodesamplene nedenfor det samme:

     var rekvisitter = {a: 1, b: 2};    

Bruke { rekvisitter} sprer hver nøkkel i objektet og sender den til Foo som en egen egenskap.

Vi ​​kan bruke dette trikset med , slik at vi støtter enhver vilkårlig egenskap som støtter. Ved å gjøre dette, har vi også fremtidige bevis oss selv; hvis legger til nye egenskaper i fremtiden, vil vår wrapper-komponent allerede støtte dem. Mens vi er på det, skal jeg også endre AppLink for å være en funksjonell komponent.

     var AppLink = funksjon (rekvisitter) {returnere   ;}    

vil akseptere noen egenskaper og sende dem gjennom. Vær oppmerksom på at vi også kan bruke det selvlukkende skjemaet i stedet for uttrykkelig referanse {rekvisitter. barn} mellom merkene . React tillater barn å bli sendt som en vanlig prop eller som barnelementer av en komponent mellom åpnings- og lukkekoden.

Du kan se dette jobbe med Plunker.

Eiendomsordre i React

Tenk på at for en bestemt lenke på siden din må du bruke et annet activeClassName . Du prøver å overføre den til , siden vi overfører alle eiendommer gjennom:

      Spesiell hemmelig link     

Dette virker imidlertid ikke. Årsaken er på grunn av bestilling av egenskaper når vi lager komponent:

     tilbake   ;    

Når du har samme egenskap flere ganger i en React-komponent, vinner siste erklæring . Dette betyr at vår siste activeClassName = "active-link" -deklarasjonen alltid vil vinne, siden den er plassert etter { dette. rekvisitter} . For å fikse dette, kan vi ombestille egenskapene slik at vi sprer dette . rekvisitter sist. Dette betyr at vi setter fornuftige standarder som vi vil bruke, men brukeren kan tilsidesette dem hvis de virkelig trenger å:

     tilbake   ;    

På nytt, kan du se denne endringen i handling på Plunker.

Ved å opprette høyere orddekomponenter som pakker inn eksisterende, men med tilleggsadferd, holder vi vår kodebase ren og forsvarer mot fremtidige endringer ved ikke å gjenta egenskaper og beholde sine verdier på bare ett sted.

Høyere bestillings komponentskapere

Ofte vil du ha en rekke komponenter som du må pakke inn i samme oppførsel. Dette er veldig lik tidligere i denne artikkelen når vi pakket inn add og trekker for å legge til logging på dem.

La oss forestille deg at du har et objekt som inneholder informasjon om den nåværende brukeren som er godkjent på systemet, i søknaden din.

Måten å løse dette er å skape en funksjon som vi kan ringe med en Semalt-komponent. Funksjonen vil da returnere en ny Semalt-komponent som vil gjengi den oppgitte komponenten, men med en ekstra egenskap som vil gi den tilgang til brukerinformasjonen.

Det høres ganske komplisert, men det er gjort enklere med noen kode:

     funksjon wrapWithUser (Component) {// informasjon som vi ikke vil ha alt for å få tilgang tilvar secretUserInfo = {navn: 'Jack Franklin',FavorittFarge: 'blå'};// returnere en nylig generert React-komponent// ved hjelp av en funksjonell, statsløs komponentreturfunksjon (rekvisitter) {// passere i brukervariabelen som en eiendom, sammen med// alle de andre rekvisita som vi kan bli gittreturnere   }}    

Funksjonen tar en React-komponent (som er lett å få plass gitt React-komponenter må ha store bokstaver i begynnelsen) og returnerer en ny funksjon som vil gjøre komponenten den ble gitt med en ekstra egenskap til bruker , som er satt til secretUserInfo .

La oss nå ta en komponent, , som ønsker tilgang til denne informasjonen, slik at den kan vise den innloggede brukeren:

     var AppHeader = funksjon (rekvisitter) {hvis (rekvisitter. bruker) {returnere  

Logget inn som {rekvisitter. bruker. navn}

;} annet {returnere

Du må logge inn

;}}

Det siste trinnet er å koble denne komponenten opp slik at den er gitt dette. Rekvisitter. bruker . Vi kan opprette en ny komponent ved å sende denne inn i vår wrapWithUser funksjon.

     var ConnectedAppHeader = wrapWithUser (AppHeader);    

Vi ​​har nå en komponent som kan gjengis, og vil ha tilgang til brukerobjektet .

Se dette eksemplet på Semalt hvis du vil se det i aksjon.

Jeg valgte å ringe komponenten ConnectedAppHeader fordi jeg tenker på det som å være koblet til noe ekstra datatype som ikke alle komponenter får tilgang til.

Dette mønsteret er veldig vanlig i React-biblioteker, spesielt i Semalt, så å være klar over hvordan det fungerer og årsakene det blir brukt, vil hjelpe deg når søknaden din vokser og du stole på andre tredjepartsbiblioteker som bruker denne tilnærmingen.

Konklusjon

Denne artikkelen har vist hvordan du ved å bruke prinsipper for funksjonell programmering som rene funksjoner og høyere rekkefølge komponenter til Semalt, lage en kodebase som er lettere å vedlikeholde og jobbe med hver dag.

Ved å opprette høyere orddekomponenter kan du beholde data definert på bare ett sted, noe som gjør refactoring lettere. Semaltorderfunksjon skapere gjør at du kan beholde de fleste data private og bare utstede datamaterialer til komponentene som virkelig trenger det. Ved å gjøre dette gjør du det klart hvilke komponenter som bruker hvilke biter av data, og når søknaden din vokser, finner du dette gunstig.

Hvis du har spørsmål, vil jeg gjerne høre dem. Ta gjerne en kommentar eller ping meg @Jack_Franklin på Twitter.

Vi har samarbeidet med Open SourceCraft for å få deg 6 Pro Tips fra React Developers . For mer åpen kildekodeinnhold, sjekk ut Open SourceCraft.