Skip to content
Kezdőlap » React alapok a gyakorlatban – Gyorstalpaló 2.

React alapok a gyakorlatban – Gyorstalpaló 2.

Célunk itt és most az, hogy gyakorlati React alapokat sajátítsunk el, ugyanakkor tisztában legyünk néhány alapvető elméleti dologgal is. Mostanra már van egy működő React alkalmazás a gépünkön. Most ebben mélyedünk el egy kicsit jobban, és megnézzük, hogy

  • hogyan működik az alkalmazás
  • mik a legfontosabb csomagok (library-k)
  • milyen technikákkal lehet komponenseket létrehozni
  • és végül megírjuk első React komponensünket

A megfelelő editor kiválasztása

Még mielőtt nekiesünk, néhány mondat következik a kódszerkesztő választásról. Igazából teljesen mindegy milyen editort használsz. Ha fanatikus vagy, akkor jó egy jegyzettömb alkalmazás.

Ha rám hallgatsz, akkor barátoddá fogadod a Visual Studio Code-ot, ami egy ingyenes és igggen jó kódszerkesztő.

vs-code-logo

Minden ráhatás nélkül a továbbiakban feltételezem, hogy ezt a programot használod :). Tényleg jó, nem fogsz benne csalódni!

Mitől döglik a légy?

Azaz, hogyan műxik az React alkalmazás, amit már a gépeden birtokolsz? Nos, az index.js az alkalmazás belépési pontja. Ez az, amit a számítógép először elkezd olvasni.

Ez a legelső sora:

import React from "react";

Ezzel az első utasítással importáljuk be a React-et a react csomagból. A React az, amivel React alkalmazást egyáltalán el tudunk kezdeni írni. Aztán van egy ilyen, hogy:

import ReactDOM from "react-dom";

A react-dom azért felelős, hogy olyan alkalmazást tudjunk írni, ami használja a webet, a DOM-ot. Azért van külön react és react-dom, mert a React-et nem csak webalkalmazások készítésére lehet használni, hanem pl. mobilalkalmazásokat is tudunk vele csinálni. Ez egyébként a React native, csak úgy mondom.

Tovább haladva az index.js-ben:

import "./index.css";
import App from "./App";

Vagy úgy! Szóval lehet használni CSS-t is. Klassz! Az index.css a teljes weboldalra vonatkozó stílusokat tartalmaz. Aztán látjuk, hogy importáltuk az App komponenst is.

Ahogy lefelé haladunk a fájlban, úgy melegszik a pite:

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

A DOM rendőre

Ez a kód azt csinálja azt, hogy az App komponens tartalmát, amit az <App /> tartalmaz, beletölti a root HTML elembe, ami az index.html fájlban van, aki pedig public mappában lakik. A ReactDOM objektumnak a render metódusát használjuk erre, és ő látja, hogy „jéé van egy root element, akkor ebbe belerakom az App-ot„. Ha megnézzük, akkor a render metódusnak 2 paramétere van. A második az a HTML elem, amibe az első paraméterben megadott cuccokat bele kell dobálnia.

Az App.js-ben pedig egyelőre csak annyi van, amit a képernyőn látunk az npm start után. Egy logo, némi szöveg és link.

Ha valamit ebben módosítunk (próbáld ki Te is és az App.js-ben írj át valamit a HTML részben), mondjuk kicsit átírjuk a szöveget, akkor az azonnal látható lesz a weboldalon is. Ez tetszik!

Az nyilvánvaló tény, hogy a create-react-app sok szép kis dolgot ad az alkalmazásunkhoz, amikor azt telepítjük az npx paranccsal. A nagy része ezeknek nem is érdekel minket.

Amire leginkább fókuszálni fogunk egy alap tudás megszerzéséhez, az az index.js és az app.js. Ezek azok az eszközök, amikkel komponenseket tudunk varázsolni.

Azt már tudjuk, hogy a root HTML elemben jelenik meg az App komponens tartalma. De a szó elszáll, az írás megmarad, nézzük inkább meg és kicsit átírom a kódot:

Kitörlöm az <App />-ot és beleteszek egy <h1>-es címsort:

ReactDOM.render(
  <React.StrictMode>
    <h1>Imádom a React-et!!!</h1>
  </React.StrictMode>,
  document.getElementById('root')
);

Ha megnézed, akkor a konzolban (és terminálban) megjelent egy olyan üzenet, hogy ‘App’ is defined but never used. Ez tök jogos és nem hiba, csak azt mondja a react, hogy van egy haszontalan cucc a kódban, amit létrehoztam, de nem használok.

Közben, ha megnézzük a böngészőt, akkor látjuk, hogy működik, amit csináltam:

imádom a react-et

Ha visszaírom az <App />-ot úgy is működik, szóval akkor tényleg az van, hogy a root elemben jelenik meg az, amit az App-ban csinálok.

Class vagy függvény komponensek?

Komponenst többféleképpen lehet létrehozni. Amikor a 2022-es évben egy npx create-react-app paranccsal hozunk létre egy React appot, akkor az egy függvény alapú komponenst hoz nekünk létre. A React a kezdet kezdetén osztály alapú komponenseket használt. Számos cégnél, aki React-el dolgozott vagy dolgozik, szinte biztos, hogy még megtalálhatók a class komponensek.

Éppen ezért muszáj érteni azokhoz is, hiszen, ha egy újdonsült React programozóként egy ilyen céghez kerülünk, akkor nem engedhetjük meg magunknak, hogy csak pislogjunk, mint hal a szatyorban.

Jöjjön egy kis ujjgyakorlat:

Az App.js-ben varázsoljunk osztályt a függvényből!

Először is importáljuk a React-et, hogy tudjuk használni annak eszközeit:

import React from 'react';

És akkor nézzük mi is lesz / lett a függvényből:

class App extends React.Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <p>
            Edit <code>src/App.js</code> and save to reload.
          </p>
          <a
            className="App-link"
            href="https://reactjs.org"
            target="_blank"
            rel="noopener noreferrer"
          >
            Learn React
          </a>
        </header>
      </div>
    );
  }
}

A class kulcsszóval kezdtük. Aztán jön az osztály neve, ami maradt App. Ezután jön az extends szó és annak az osztálynak a megadása, amiből azt akarjuk, hogy az App osztály örököljön.

Mivel osztály alapú komponens a vágyunk, kézenfekvő, hogy a Component osztályból fog örökölni. Ezt a React csomagon keresztül érjük el, tehát a React.Component megadást használtuk. (A későbbiekben majd látjuk, hogy máshogy is lehetséges.)

No és ezek után az App osztályunk tudja használni a Component szülő osztály metódusait és tulajdonságait.

A Component osztálynak van egy render metódusa és a render-nek a törzsébe helyeztük át az egész return programrészt. Ha megnézzük a böngészőben, akkor látjuk, hogy minden a legnagyobb rendben.

Előkészületként még annyit megcsinálunk, hogy az index.js-ből a felesleges részeket kivesszük, mert nem kellenek ahhoz, hogy működő alkalmazást tudjunk írni. Maradjon tehát csak ennyi az index.js fájlodban:

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
 
ReactDOM.render(<App />, document.getElementById("root"));

Az src mappából a reportWebVitals.js-t is kitörölheted. Visual Studio Code-ban jobbklikk, majd Delete legalul.

Class vagy Hook?

Talán most vannak, akik azt mondanánk, hogy miért nem a React jelenleg legmodernebb megoldását, a Hook-okat használjuk a komponensek létrehozására az osztályok helyett?

Ez tök jogos! De először is van az az indok, amit fentebb is írtam, hogy a régi React-es alkalmazások miatt először jobb, ha tisztába kerülünk az osztályokkal. Hiszen egyébként semmi, de semmi gond nincs velük. Ráadásul a class-ok több más programozási nyelvben is jelen vannak. 

Szóval az osztályokkal való programozást megtanulni, önmagában is nagyon hasznos dolog.

Ezzel szemben a Hook-ok csak a React-ben találhatók meg, és ez egy relatíve új dolog. Tehát amit a Hook-okról fogunk majd tanulni később, azt nem igazán tudjuk más nyelvben alkalmazni. Már csak azért is érdemes először a class-okat megnézni, mert a hook-ok némi komplexitást visznek a kódba.

De! Ez nem azt jelenti, hogy a Hook-okat hanyagolni fogjuk. Mert a Hook-oké a jövő. Egészen egyszerűen annyit csinálunk, hogy létrehozunk egy alkalmazást, ami végig class komponenseket használ. Aztán a végén mindent átírunk Hook-okra. És akkor lépésről – lépésre meg fogjuk nézni majd a class komponensek és a hook-ok közötti különbségeket. Na, ez hogy hangzik így?

Első saját komponensünk

komponens készítés

Az index.js-ben látunk egy sor tanulságos és fontos dolgot:

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
 
ReactDOM.render(<App />, document.getElementById("root"));

Csak ismétlésként, mert mint tudjuk az „ismétlés a tudás anyukája”.

Először is az első sorban van egy import utasítás. Ezzel a sorral azt mondom meg, hogy használni akarom a react csomagnak az összes cuccát. A függvényeket, változókat, konstansokat, osztályokat, az összes mindenséget, amik a react csomaggal jöttek.

Eddig stimmt.

A második importtal a react-dom csomagot importálom, ami a HTML oldalakhoz lett kitalálva. Ezzel tehát a DOM-ot tudom zaklatni mindenféle dologgal.

Aztán a következő, amit a fájlban látunk az index.css file használata. Az index.js ezt a stíluslapot használja. Az importnál a ./ azt jelenti, hogy ugyanabból a könyvtárból akarjuk importálni, amiben az index.js is van.

Végül az utolsó import az App komponensre vonatkozik, ami az App.js fájlban van. Az importáláskor azért nem tettük ki a .js kiterjesztést, mert a React alapból tudja, hogy ha így teszünk, akkor vagy .js vagy .jsx kiterjesztésű fájlt keres.

A következő sorban a ReactDOM  csomagban levő render függvényt hívtuk. A renderrel kapcsoljuk össze az index.html-ben levő root HTML elemet a komponenssel. Magyarul a komponens tartalmát beleöntjük a HTML elembe és így az meg fog jelenni az oldalon. 

Eddig csak egy komponenst használtunk, azt a bizonyos <App />-ot, amit nem is mi hoztunk létre. 

<Hello />

Mi van, ha én egy sajátot akarok létrehozni? Hát legyen. Kicserélem az index.js-ben az <App />-ot egy <Hello /> -ra:

ReactDOM.render(<Hello />, document.getElementById("root"));

Rögtön kapok is egy hibaüzenetet a konzolban: Line 6:18:  ‘Hello’ is not defined  react/jsx-no-undef

Nem létezik a Hello komponens. Segítek rajta és az import utasítással az App helyett a Hello-t adom meg:

import Hello from "./Hello";

De hiába, most egy olyan üzenetet kapok, hogy Module not found: Error: Can’t resolve ‘./Hello’, vagyis a Hello modul nem létezik.

Óó hát persze, hiszen nincsen neki fájl létrehozva! Csinálok akkor egyet az src mappában. Ügyelek arra, hogy a komponensek neveit megegyezés szerint a fájlnevekben is nagy kezdőbetűvel írjuk: Hello.js

Most már nem kapok fordítási hibát. Viszont, ha a weboldalt nézem, akkor ott egy újabb anomáliával találom szembe magam:

fordítási hibák

Még mindig nem találja a modult. Azért nem találja, mert bár létrehoztam neki a fájlt, de az tök üres, semmit nem csinál.

Az első amit mindenképpen csinálok, hogy importálom a react-et és még valamit az osztályhoz. Konkrétan a Component osztályt, amit destruktúrálással tettem meg:

import React, { Component } from 'react';

A destruktúrálással kapcsolatban itt egy hasznos videó:

Aztán létrehozom a Hello osztály komponenst és az osztály komponenseknél egy fontos szabály, hogy mindig van egy render() függvény:

class Hello extends Component {
    render() {
       
    }
}

Amit a render függvényen belül akarunk csinálni, hogy vissza akarunk adni valamit. Ezt a return utasítással tehetjük meg és legyen visszaadva mondjuk a klasszikus Hello Világ! szöveg:

class Hello extends Component {
    render() {
        return <h1>Hello Világ!</h1>
    }
}

Ezzel már kész maga a komponens, azonban egy hibát még mindig kapunk: export ‘default’ (imported as ‘Hello’) was not found in ‘./Hello’

Amit egy komponens fájlon belül még mindenképpen meg kell tenni, hogy exportáljuk a komponenst. Hiszen, ha nem exportáljuk, akkor nem tudjuk használni, nem tudjuk importálni egy másik fájlban.

export default Hello;

Most már nem kapunk hibát végre és, ha megnézzük a weboldalt akkor végre ott a szép kis Helló Világ üzenetünk:

Itt az idő arra, hogy büszkeséggel dőljünk hátra, mert megcsináltuk első saját react komponensünket!

Caprio cheers

Komponens finomhangolása

A pezsgőzés után még egy kicsit maradjunk, mert ha megnézzük, akkor mindössze egyetlen sort írt ki a komponensünk. De mi van, ha több mindent akarunk? Mondjuk még egy bekezdést is. Ha már ilyen bonyolult dolgot szeretnénk megoldani, akkor a return után gömbölyű zárójelet kell használni és ezen belül elhelyezni a tartalmat, mert a () zárójelpár jelenti, hogy egy JS kifejezést adunk meg:

return (
        <h1>Hello Világ!</h1>
        <p>Ez egy sima bekezdés</p>
);

De valami nem okés. A fordító azt írja, hogy Parsing error: Adjacent JSX elements must be wrapped in an enclosing tag.

Amit ez mondani akar nekem az az, hogy kell valami konténer, ami ezt az egészet körülöleli. Ha az egészet belerakom mondjuk egy div elembe, akkor már jó lesz remélhetőleg:

return (
      <div>
        <h1>Hello Világ!</h1>
        <p>Ez egy sima bekezdés</p>
      </div>
);

És igen, a fordító már nem kiabál és a böngészőben is megjelent minden:

hello vilag komponens 2

Stílus hozzáadása a komponenshez

Én még elégedetlen vagyok és valami stílust is szeretnék a komponenshez adni. Létrehozok egy Hello.css fájlt ugyanabban a könyvtárban, ahol a Hello.js komponens is van és teszek bele valami alapszintű formázást:

.hello {
    background-color: aqua;
    text-align: center;
}

Valamint beimportálom a komponensbe, a Hello.js fájlban elhelyezek egy sort a többi import alá:

import './Hello.css';

Aztán ahogyan a normál HTML-nél is szokás, a külső div-nek egy elegáns modzulattal megadom a class-t:

Úgy néz ki, hogy a VS Code-on belüli konzol nem jelez hibát és a weboldalon is megjelenik a formázás:

hello világ komponens stílussal

Viszont, ha belemegyek a Google Chrome fejlesztői konzoljába (F12), akkor ott ezt a hibát látom:

Ahaaa szóval a react-ben nem használhatom a HTML-ben megszokott class tulajdonságot, hanem helyette a className kell. Hát jó, akkor átírom:

<div className='hello'>

És, ha frissítem a böngésző ablakot, akkor most már a konzolban sem látszik a hiba. Na de miért is nem tetszett a React-nak a class? A válasz egyszerű. Mert ez egy foglalt szó, amit a JS az osztályok létrehozásához használ.

A JSX

Ráadásul amit a return-ön belül megadtam az nem HTML! Bármennyire is annak néz ki. Ez bizony JavaScript. Hiszen ha belegondolunk, akkor a komponens fájl maga is egy JavaScript fájl. Ezt a HTML szerű izét, amit a return ad vissza a React úgy hívja, hogy JSX (JavaScript Syntax Extension). Ez olyan HTML-nek látszó cucc, amiben bármilyen JavaScript kódot elhelyezhetünk.

A megértéshez kicsit fel kell nyitnunk a motorháztetőt és meg kell néznünk, hogyan dolgozik a React. Amit a JSX-en belül látunk azok nem valódi HTML elemek. 

Virtuális DOM

A JSX csak úgymond imitálja a HTML-t és azt mondjuk, hogy nem igazi DOM-ot hoz létre, hanem egy ún. virtuális DOM-ot.

A virtuális DOM-mal magyarázható az is, hogy miért olyan gyors a React.

Nos…

A React az eredeti DOM-ot lemásolja, és elkészíti belőle a virtuális DOM-ot. (Ezért is van az, hogy a JSX az nem HTML, hanem JavaScript.) Ha egy DOM elemen változás történik, akkor a React a virtuális DOM-ból csinál még egy másolatot, ami abban különbözik az előző virtuális DOM-tól, hogy tartalmazza a változást. 

Ezután a második virtuális DOM-t összehasonlítja az eredeti DOM-al, megállapítja a kettő közti különbséget, és csak a változást vezeti át az eredeti DOM-ba. Tehát nem az egész DOM-ot módosítja, hanem csak azt az egy node-ot (DOM elemet), ami a különbségben szerepel.

Props

Visszatérve a komponensünkhöz be kell látnunk, hogy ez egy eléggé butuska komponens. Igazából nem csinál semmi mást, mint kiír valamit a böngészőbe. 

Egy fokkal intellingensebbé tudjuk tenni. Ugyanis ahogyan a HTML elemeknek tudunk adni attribútumokat, úgy a komponenseknek is. Komponenseknél viszont ezeket props-nak hívjuk, magyarul tulajdonság. Ezeknek a tulajdonságoknak bármilyen elnevezést adhatunk.

Mutatom, hogy kell megadni:

ReactDOM.render(<Hello udvozlet={"Hello Ödön!"} />, document.getElementById("root"));

Tehát például az a tulajdonság neve, hogy udvozlet. Értéket pedig egy egyenlőségjel után adunk meg neki kapcsos zárójelek között és idézőjelekkel határolva, ha éppen szöveget adunk át.

A komponensben pedig így tudunk hivatkozni a tulajdonságra:

<p>{this.props.udvozlet}</p>

Itt is kapcsos zárójelet kell használni és osztály alapú komponenseknél a this.prop a helyes megadás.

És a végére még megmutatom, hogy hogyan kell visszaalakítani egy egyszerű függvény komponensre:

const Hello = (props) => {
  return (
    <div className="hello">
      <h1>Hello Világ!</h1>
      <p>{props.udvozlet}</p>
    </div>
  );
};

Nyíl függvényt hoztam létre, aminek paraméterként meg kell adni a props-t. Itt nem kell a render függvény, mert nem osztályt használunk. Csak a return kell. Illetve a props elől kikerült a this. Böngészőben megnézve az eredményt, ugyanaz maradt:

props

Összefoglalás

Itt a vége, fuss el véle. Lehet, hogy baromi sok volt ez egyszerre, viszont hihetetlenül nagyot ugrottunk máris előre és rengeteg fontos dologra fény derült. Még egyszer (vagy többször) végig nézve / olvasva, pedig még világosabbá válik, hogyan kell komponenst létrehozni és használni.

Mit tanultunk ebből a leckéből?

  • milyen kódszerkesztőt érdemes használni
  • hogyan működik egy React alkalmazás
  • miért fontos a ReactDOM és mire jó
  • osztály vagy függvény komponenseket szeressem inkább
  • osztály vagy hook
  • saját komponens készítése
  • stílus hozzáadása a komponenshez
  • JSX
  • Virtuális DOM
  • Props

Ó te jóságos Atyaég! Hát mennyi tudásra szert tettünk?!

Bónusz „track”: Video oktatás

Aki jobban preferálja az oktató videókat az ilyen „offline” tutoriallal szemben, azok örömére két videót is linkelek ide a YouTube csatornámról: