Főoldal

"Mérnököt a mérnöktől"

A Schönherz Bázis összeköti az állást kereső és állást kínáló mérnököket.

CV küldés

Küldj önéletrajzot! Gyorsan, egyszerűen.
Megjegyzésbe írd be a pozíció nevét.
CV küldés

Iratkozz fel hírlevelünkre!

Hírek

A React fejlődő mintái
A React fejlődő mintái

Ebben a cikkben közelebbről megnézzük React világában jelenleg feltörekvő minták egy részét. Ezek a minták javítják az olvashatóságot, a kód átláthatóságát, illetve a kompozíció és újrafelhasználhatóság felé viszik a kódot.  

Durván 3 évvel ezelőtt kezdtem el a React-tel dolgozni. Abban az időben nem voltak bevett gyakorlatok, melyekből megtanulhattam volna kihasználni a lehetőségeit.

A közösségnek két évbe telt, mire néhány ötletben megállapodtak. Váltottunk a React.createClass-ról az ES6 class-ra és tisztán funkcionális komponensekre. Elhagytuk a mixineket és egyszerűsítettük az API-kat.

Most, hogy a közösség nagyobb, mint valaha, néhány igényes minta látszik kifejlődni.

Annak érdekében, hogy megértsük ezeket a mintákat, szükségünk van egy átfogó alaptudásra a React koncepcióiról és világáról, melyet ez a cikk nem fog megadni, így javasolt azt máshol elolvasni.

Kezdjük is el!


Feltételes renderelés

Az alábbi forgatókönyvet rengeteg projektben látom.

Amikor az emberek találkoznak a React és JSX kifejezésekkel, még mindig a HTML-lel és JavaScripttel kapcsolatban gondolkoznak.

Szóval a természetes lépés, hogy elválasztjuk a feltételes logikát a tényleges visszatérési kódtól.

const condition = true;


const App = () => {

  const innerContent = condition ? (

    <div>

      <h2>Show me</h2>

      <p>Description</p>

    </div>

  ) : null;


  return (

    <div>

      <h1>This is always visible</h1>

      { innerContent }

    </div>

  );

};


Ez hajlamos irányíthatatlanná válni, többszörös ternárissal minden egyes render függvény elején. Folyamatosan bele kell ugrani a függvénybe, hogy megtudjuk, egy bizonyos elem renderelt-e vagy sem.

Alternatívaként ki lehet próbálni a következő mintát, ahol a nyelv végrehajtási modelljéből előnyt tudunk kovácsolni.


const condition = true;


const App = () => (

  <div>

    <h1>This is always visible</h1>

    {

      condition && (

        <div>

          <h2>Show me</h2>

          <p>Description</p>

        </div>

      )

    }

  </div>

);


Ha a feltétel (condition) hamis, az && operátor második operandusa nem értékelődik ki. Ha viszont igaz, akkor a második operandus – vagy a renderelni vágyott JSX – lesz a visszatérési érték.

Ez lehetővé teszi nekünk a felhasználói felület logikájának deklaratív módú elegyítését a tényleges UI elemekkel. Kezeld úgy a JSX-et, mintha az a kód beépített része lenne. Hiszen az is csak JavaScript!


Paraméterek továbbítása

Amikor az alkalmazás nő, kisebb komponensek vannak, melyek más komponensek tárolójaként funkcionálnak.

Amikor ez megtörténik, paraméterek tömkelegét kell átadnod a komponensen keresztül. A komponensnek nincs szüksége ezekre, de a „gyerekeinek” igen. Ennek megkerülésére egy remek módszer a paraméterek destrukturálásának és a JSX spread-nek az együttes használata, ahogy az itt is látható:


const Details = ( { name, language } ) => (

  <div>

    <p>{ name } works with { language }</p>

  </div>

);



const Layout = ( { title, ...props } ) => (

  <div>

    <h1>{ title }</h1>

    <Details { ...props } />

  </div>

);



const App = () => (

  <Layout

    title="I'm here to stay"

    language="JavaScript"

    name="Alex"

  />

);


Így már meg tudod változtatni a Details-hez szükséges paramétereket, és biztos lehetsz benne, hogy ezekre nincs többszörös hivatkozás a különböző komponensekben.


A paraméterek destrukturálása

Egy alkalmazás az idő elteltével változik, csakúgy, mint a komponensek. Egy két évvel ezelőtt írt komponens lehet állapot-teljes, de akár át is lehet alakítani állapotmentessé. Ez a folyamat fordítva is megtörténik egy csomószor!

Mivel már beszéltünk a paraméterek destrukturálásáról, itt egy trükk, melyet az életem hosszútávú megkönnyítésére használok. Mindkét féle komponensben hasonlóképp tudod ezt a folyamatot véghez vinni:


const Details = ( { name, language } ) => (

  <div>

    <p>{ name } works with { language }</p>

  </div>

);



class Details extends React.Component {

  render() {

    const { name, language } = this.props;

    return (

      <div>

        <p>{ name } works with { language }</p>

      </div>

    )

  }

}


Vegyük észre, hogy a 2-4. és a 11-13. sorok hasonlóak. A komponensek átalakítása sokkal könnyebb ennek a mintának az alkalmazásával. Emellett a komponens belsejében a this használatát lekorlátozzuk.


Provider minta

Megnéztünk egy mintát, ahol a paramétereket másik komponensen keresztül kell átadnunk. De mi történik akkor, ha 15 komponensen keresztül kell ezt megtenni?

Itt jön képbe a React Context.

Ez nem feltétlenül a React legajánlottabb része, de teszi a dolgát, amikor szükségünk van rá. Nem olyan régen bejelentették, hogy a Context kap egy új API-t, mely implementálja a provider mintát. Ha használsz a React Reduxhoz vagy Apollohoz hasonló dolgokat, akkor esetleg ismerős lehet ez.

A mostani API működését látva könnyen meg fogod érteni, hogyan működik az új API. Ez a sandbox erre tökéletes, el lehet vele játszadozni.

A legmagasabb szintű komponens – melyet Providernek nevezünk – elhelyez néhány értéket a környezetben, melyeket a gyermek – vagy Consumernek nevezett – komponensek megragadnak.

A jelenlegi kontextus szintaxisa egy kicsit furcsa, de a közelgő verzió is pontosan ezt a mintát fogja implementálni.


Magasabb rendű „High Order” komponensek

Beszéljünk egy kicsit az újrafelhasználhatóságról. A régi React.createElement() elhagyásával egyidőben a React csapata befejezte a mixinek támogatását. Egy bizonyos ponton ezek adták a komponensek összeállításának standard módját egyszerű objektumkompozíción keresztül.

A magasabb rendű komponensek – mostantól HOC – a különböző viselkedések komponensek közötti újrafelhasználásának céljából jöttek létre. Ezek olyan függvények, melyek az átvett komponens egy javított/módosított változatát adják vissza. A HOC-okat különböző néven fogod megtalálni, de én leginkább díszítőknek szeretem hívni őket.


Ha Reduxot használsz, fel fogod ismerni, hogy a connect függvény egy HOC – átveszi a komponenst, és hozzáad egy csomó paramétert.

Implementáljunk egy egyszerű HOC-ot, mely hozzá tud adni paramétereket a létező komponensekhez.


const withProps = ( newProps ) => ( WrappedComponent ) => {

  const ModifiedComponent = ( ownProps ) => ( // the modified version of the component

    <WrappedComponent { ...ownProps } { ...newProps } /> // original props + new props

  );



  return ModifiedComponent;

};



const Details = ( { name, title, language } ) => (

  <div>

    <h1>{ title }</h1>

    <p>{ name } works with { language }</p>

  </div>

);


const newProps = { name: "Alex" }; // this is added by the hoc

const ModifiedDetails = withProps( newProps )( Details ); // hoc is curried for readability


const App = () => (

  <ModifiedDetails

    title="I'm here to stay"

    language="JavaScript"

  />

);


Ha szereted a funkcionális programozást, akkor imádni fogsz magasabb rendű komponensekkel dolgozni. A Recompose egy remek csomag, mely tartalmaz egy csomó hasznos HOC-ot, mint például a withProps, withContext, lifecycle, és így tovább.

Nézzük meg az újrafelhasználó funkcionalitás egy hasznos példáját.


function withAuthentication(WrappedComponent) {

const ModifiedComponent = (props) => {

   if (!props.isAuthenticated) {

      return <Redirect to="/login" />;

    }



    return (<WrappedComponent { ...props } />);

  };



  const mapStateToProps = (state) => ({

    isAuthenticated: state.session.isAuthenticated

  });



  return connect(mapStateToProps)(ModifiedComponent);

}


A withAuthentication-t akármikor használhatod, ha bizalmas tartalmakat szeretnél renderelni egy route folyamán. Így az a tartalom csak bejelentkezett felhasználók számára lesz elérhető.

Ez egy más problémákat is érintő probléma az egy helyen implementált, de az egész alkalmazásban több helyen is felhasznált kódnál.

Azonban a HOC-nak van egy árnyoldala is. Minden egyes HOC bevezet egy új React komponenst a DOM/vDOM struktúrádba. Ez lehetséges teljesítménybeli problémákhoz vezethet, ahogy az alkalmazásod növekszik.

Még néhány felmerülő problémát ebben a nagyszerű cikkben foglalt össze Michael Jackson. Ő a HOC-ok helyett a következőkben tárgyalt minta használatát pártolja.


Render Props

Bár igaz, hogy a render prop-ok és HOC-ok felcserélhetők, én mégsem pártolom egyiket sem jobban, mint a másikat. Mindkét minta a kód újrafelhasználhatóságát és átláthatóságát javítja.

Az ötlet az, hogy átadod a render függvényed irányítását egy másik komponensnek, mely aztán azt egy függvényparaméteren keresztül adja vissza neked.

Néhány programozó a dinamikus propokat preferálja ehhez, mások csak szimplán a this.props.children-t használják.

Tudom, hogy még mindig nagyon zavaros, de nézzünk meg egy egyszerű példát.


class ScrollPosition extends React.Component {

  constructor( ) {

    super( );

    this.state = { position: 0 };

    this.updatePosition = this.updatePosition.bind(this);

  }


  componentDidMount( ) {

    window.addEventListener( "scroll", this.updatePosition );

  }


  updatePosition( ) {

    this.setState( { position: window.pageYOffset } )

  }


  render( ) {

    return this.props.children( this.state.position )

  }

}


const App = () => (

  <div>

    <ScrollPosition>

      { ( position ) => (

        <div>

          <h1>Hello World</h1>

          <p>You are at { position }</p>

        </div>

      ) }

    </ScrollPosition>

  </div>

);


Itt mi a children-t használjuk render prop-ként. A <ScrollPosition> komponens belsejében egy függvényt küldünk, mely a position-t kapja meg paraméterként.

A render propokat olyan szituációkban tudod használni, ahol a komponens belsejében van szükséged újrafelhasználható logikára, és nem akarod a komponensed egy HOC-ba csomagolni.

A React-Motion egy könyvtár, mely néhány remek példát nyújt a render propok használatára.

Végül nézzük meg, hogyan tudjuk integrálni az aszinkron folyamokat ennek segítségével. Itt egy szép példája egy újrafelhasználható Fetch komponens létrehozásának.

Megosztok egy sandbox linket, így el tudtok játszani vele, és láthatjátok az eredményeket.

Használhatsz akár több render propot is ugyanabban a komponensben. Ezzel a mintával végtelen lehetőséged van funkcionalitások létrehozásához és újrafelhasználásához.


(Forrás


Ha Te is kreatív, kihívásokkal teli mérnök állást keresel minõségi munkáltatónál, jó helyen jársz, mert a Schönherz Bázis épp azért jött létre, hogy Neked segítsen.
Gyere, nézz szét aktuális állásaink között!