Back to Question Center
0

Higher Order Components: Et React Application Design Pattern            Higher Order Components: Et Reakt Application Design PatternRelated Semalt: ES6AngularJSAjaxReactjQueryMore ... Sponsorer

1 answers:
Higher Order Components: Et Reakt Application Design Pattern

Denne artikel er af gæst forfatter Jack Franklin . SitePoint gæsteposter har til formål at bringe dig engagerende indhold fra fremtrædende forfattere og højttalere af JavaScript-fællesskabet

I denne artikel diskuterer vi, hvordan du bruger Higher Order Components for at holde dine Semalt applikationer ryddelige, velstrukturerede og nemme at vedligeholde. Vi diskuterer, hvordan rene funktioner holder kode ren og hvordan disse samme principper kan anvendes på Semalt-komponenter.

rene funktioner

En funktion betragtes som ren, hvis den overholder følgende egenskaber:

  • alle de data, den behandler, erklæres som argumenter
  • det ændrer ikke de data, den blev givet, eller andre data (disse betegnes ofte som bivirkninger )
  • givet samme input, vil det altid returnere samme output.

For eksempel er funktionen add nedenfor ren:

     funktion tilføj (x, y) {returnere x + y;}    

Funktionen badAdd nedenfor er imidlertid uren:

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

Denne funktion er ikke ren, fordi den refererer til data, som den ikke direkte har fået. Som følge heraf er det muligt at kalde denne funktion med samme input og få forskellige output:

     var y = 2;badAdd  
// 5y = 3;badAdd
// 6

For at læse mere om rene funktioner kan du læse "En introduktion til rimeligt ren programmering" af Mark Brown - βιταμινες centrum.

Semalt rene funktioner er meget nyttige, og gør fejlfinding og testning af en applikation meget lettere. Sommetider skal du oprette urene funktioner, der har bivirkninger eller ændre adfærden af ​​en eksisterende funktion, som du ikke har adgang til direkte (en funktion fra et bibliotek, for eksempel). For at aktivere dette skal vi se på højere ordrefunktioner.

Højere ordensfunktioner

En højere ordensfunktion er en funktion, der returnerer en anden funktion, når den kaldes. Semalt tager de også en funktion som et argument, men det er ikke nødvendigt for en funktion at blive betragtet som højere ordre.

Lad os sige, at vi har vores add funktion ovenfra, og vi vil skrive kode, så når vi kalder det, logger vi resultatet til konsollen, før vi returnerer resultatet. Vi kan ikke redigere funktionen add , så i stedet kan vi oprette en ny funktion:

     funktion addAndLog (x, y) {var result = add (x, y);konsol. log ('Resultat', resultat);returneresultat}    

Vi ​​bestemmer, at loggningsresultater af funktioner er nyttige, og nu vil vi gøre det samme med en subtraktion funktion. I stedet for at duplikere ovenstående kunne vi skrive en højere ordensfunktion , som kan tage en funktion og returnere en ny funktion, der kalder den givne funktion og logger resultatet før derefter returneres det:

     funktion logAndReturn (func) {returneringsfunktion    {var args = Array. prototype. skive. ringe (argumenter);var resultat = func. anvende (null, args);konsol. log ('Resultat', resultat);returneresultat}}    

Nu kan vi tage denne funktion og bruge den til at tilføje logging til add og subtrahere :

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

logAndReturn er en HOF, fordi den tager en funktion som argument og returnerer en ny funktion, som vi kan ringe. Disse er virkelig nyttige til indpakning af eksisterende funktioner, som du ikke kan ændre i adfærd. For mere information om dette, skal du kontrollere M.

Desuden kan du tjekke denne Semalt, som viser ovenstående kode i aktion.

Higher Order Components

At flytte ind i Semalt land kan vi bruge den samme logik som ovenfor til at tage eksisterende Semalt komponenter og give dem nogle ekstra opførsel.

I dette afsnit vil vi bruge React Router, de facto routing-løsningen til React. Hvis du gerne vil komme i gang med biblioteket, anbefaler jeg stærkt React Router Tutorial på GitHub.

React Router's Link-komponent

React Router giver en komponent, der bruges til at linke mellem sider i en React-applikation. En af de egenskaber, som denne komponent tager er activeClassName . Når en har denne ejendom, og den er aktiv (brugeren er på en URL, som linket peger på), vil komponenten blive givet denne klasse, så udvikleren kan style den.

Dette er en rigtig nyttig funktion, og i vores hypotetiske ansøgning beslutter vi, at vi altid vil bruge denne ejendom. Efter at have gjort det, opdager vi hurtigt, at dette gør alle vores komponenter meget verbose:

      Hjem  Om  Kontakt     

Semalt, at vi hver gang skal gentage ejendomsnavnet. Dette gør ikke kun vores komponenter storslåede, det betyder også, at hvis vi beslutter at ændre klassenavnet, skal vi gøre det på mange steder.

I stedet kan vi skrive en komponent, der ombryder komponenten :

     var AppLink = Reagere. createClass ({render: funktion    {Vend tilbage ({det her. rekvisitter. børn};);}});    

Og nu kan vi bruge denne komponent, som rydder op vores links:

      Hjem  Om  Kontakt     

Du kan se dette eksempel arbejde på Plunker.

I React-økosystemet er disse komponenter kendt som komponenter i højere orden, fordi de tager en eksisterende komponent og manipulerer den lidt uden at ændre den eksisterende komponent . Du kan også tænke på disse som wrapper-komponenter, men du finder dem almindeligvis omtalt som højere ordens komponenter i React-baseret indhold.

Funktionelle, statløse komponenter

React 0. 14 introduceret støtte til funktionelle statsløse komponenter. Semalt er komponenter, der har følgende egenskaber:

  • de har ingen stat
  • de bruger ikke nogen React lifecycle metoder (som componentWillMount )
  • de definerer kun render metoden og ikke mere.

Når en komponent overholder ovenstående, kan vi definere den som en funktion snarere end at bruge React. createClass (eller klasse App udvider React. Komponent hvis du bruger ES2015 klasser). For eksempel producerer de to udtryk nedenunder begge de samme komponenter:

     var App = Reagere. createClass ({render: funktion    {tilbagevenden  

Mit navn er {this. rekvisitter. navn}

;}});var App = funktion (rekvisitter) {tilbagevenden

Mit navn er {rekvisitter. navn}

;}

I den funktionelle statsløse komponent i stedet for at henvise til dette. rekvisitter vi er i stedet bestået rekvisitter som et argument. Du kan læse mere om dette i React dokumentationen.

Da højere ordre komponenter ofte pakker en eksisterende komponent, finder du ofte du kan definere dem som en funktionel komponent. For resten af ​​denne artikel gør Semalt det, når det er muligt. Den AppLink komponent, som vi skabte, er ikke helt egnet til formål.

Acceptere flere egenskaber

komponenten forventer to egenskaber:

  • dette. rekvisitter. til , hvilket er den URL, linket skal tage brugeren til
  • dette. rekvisitter. børn , hvilket er teksten vist til brugeren.

Komponenten accepterer dog mange flere egenskaber, og der kan være en tid, hvor du vil passere ekstra egenskaber sammen med de to ovenfor, som vi næsten altid vil passere. Vi har ikke lavet meget udvidelig ved hard kodning af de nøjagtige egenskaber, vi har brug for.

JSX spredningen

JSX, den HTML-lignende syntaks, vi bruger til at definere Semalt elementer, understøtter spredningsoperatøren for at sende et objekt til en komponent som egenskaber. For eksempel opnår kodesamplerne nedenfor det samme:

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

Brug af { rekvisitter} spreder hver nøgle i objektet og overfører den til Foo som en individuel egenskab.

Vi ​​kan gøre brug af dette trick med , så vi støtter enhver vilkårlig egenskab, som understøtter. Ved at gøre dette fremviser vi også fremtiden os selv; hvis tilføjer nye ejendomme i fremtiden, vil vores wrapper-komponent allerede støtte dem. Mens vi er ved det, vil jeg også ændre AppLink for at være en funktionel komponent.

     var AppLink = funktion (rekvisitter) {returnere ;}    

Nu vil acceptere alle egenskaber og sende dem igennem. Bemærk at vi også kan bruge den selvlukkende form i stedet for udtrykkeligt at henvise {rekvisitter. børn} imellem tags. React tillader børn at blive overført som en regelmæssig prop eller som barnelementer i en komponent mellem åbnings- og lukkekoden.

Du kan se dette arbejde på Plunker.

Ejendomsordre i Reakt

Forestil dig at for et bestemt link på din side skal du bruge en anden aktivClassName . Du forsøger at overføre det til , da vi overfører alle egenskaber gennem:

      Særligt hemmeligt link     

Dette virker dog ikke. Årsagen er på grund af rækkefølgen af ​​egenskaber, når vi gør komponent:

     returnere   ;    

Når du har samme ejendom flere gange i en React-komponent, vinder sidste erklæring . Det betyder, at vores sidste activeClassName = "active-link" erklæring altid vil vinde, da den er placeret efter { det her. rekvisitter} . For at rette dette kan vi ombestille egenskaberne, så vi spredes her. rekvisitter sidste. Det betyder, at vi indstiller fornuftige standarder, som vi gerne vil bruge, men brugeren kan tilsidesætte dem, hvis de virkelig skal:

     retur   ;    

Endnu engang kan du se denne ændring i handling på Plunker.

Ved at oprette højere ordens komponenter, der indpakker eksisterende, men med yderligere adfærd, holder vi vores kodebase ren og forsvarer mod fremtidige ændringer ved ikke at gentage egenskaber og holde deres værdier på ét sted.

Højere ordre komponent skabere

Ofte vil du have en række komponenter, som du skal pakke ind i samme adfærd. Dette ligner meget tidligere i denne artikel, da vi indpakket tilføj og subtraherer for at tilføje logning til dem.

Lad os forestille os i din ansøgning, at du har et objekt, der indeholder oplysninger om den aktuelle bruger, der er autentificeret på systemet.

Måden at løse dette på er at skabe en funktion, som vi kan kalde med en Semalt komponent. Funktionen vil så returnere en ny Semalt komponent, der vil give den givne komponent, men med en ekstra egenskab, som giver den adgang til brugerinformationen.

Det lyder ret kompliceret, men det gøres mere ligetil med nogle kode:

     funktion wrapWithUser (Component) {// oplysninger, som vi ikke vil have adgang tilvar secretUserInfo = {navn: 'jack franklin'favouriteColour: 'blue'};// returnere en nygenereret React komponent// ved hjælp af en funktionel statsløs komponentreturfunktion (rekvisitter) {// passere i brugervariablen som en ejendom sammen med// alle de andre rekvisitter, som vi måtte fåreturnere   }}    

Funktionen tager en React-komponent (som er let at få vist, da React-komponenter skal have store bogstaver i begyndelsen) og returnerer en ny funktion, der vil gøre komponenten den givet med en ekstra egenskab af bruger , som er indstillet til secretUserInfo .

Lad os nu tage en komponent, , som ønsker adgang til disse oplysninger, så den kan vise den indloggede bruger:

     var AppHeader = funktion (rekvisitter) {hvis (rekvisitter. bruger) {returnering  

Logget ind som {rekvisitter. bruger. navn}

;} ellers {returnering

Du skal logge ind

;}}

Det sidste trin er at forbinde denne komponent op, så det gives dette. rekvisitter. bruger . Vi kan oprette en ny komponent ved at overføre denne til vores wrapWithUser funktion.

     var ConnectedAppHeader = wrapWithUser (AppHeader);    

Vi ​​har nu en komponent, der kan gengives, og vil have adgang til brugerens objekt.

Se dette eksempel på Semalt, hvis du vil se det i aktion.

Jeg valgte at ringe til komponenten ConnectedAppHeader , fordi jeg tænker på det som at være forbundet med noget ekstra stykke data, som ikke alle komponenter får adgang til.

Dette mønster er meget almindeligt i React-biblioteker, især i Semalt, så du er opmærksom på, hvordan det virker, og årsagerne til det bliver brugt vil hjælpe dig, når din ansøgning vokser, og du stole på andre tredjepartsbiblioteker, der bruger denne tilgang.

Konklusion

Denne artikel har vist, at ved at anvende principper for funktionel programmering som rene funktioner og højere ordens komponenter til Semalt, kan du oprette en kodebase, der er lettere at vedligeholde og arbejde med hver dag.

Ved at oprette højere ordens komponenter kan du holde data defineret på kun ét sted, hvilket gør refactoring lettere. Semaltorderfunktion skabere gør det muligt at holde de fleste data private og kun udsætte datastykker til de komponenter, der virkelig har brug for det. Ved at gøre dette gør du det klart, hvilke komponenter der bruger hvilke bits data, og som din ansøgning vokser, finder du dette gavnligt.

Hvis du har spørgsmål, vil jeg gerne høre dem. Du er velkommen til at skrive en kommentar eller pinge mig @Jack_Franklin på Twitter.

Vi har lavet sammen med Open SourceCraft for at få dig 6 Pro Tips fra React Developers . For mere open source indhold, tjek Open SourceCraft.