A React egy JavaScript alapú könyvtár, amelyet a Facebook fejlesztett ki. A React kifejezetten felhasználói felületek (UI) építésére szolgál, és különösen népszerű az egyoldalas alkalmazások (SPA Single Page App) készítése során.
A REACT komponensalapú keretrendszer.
A React virtuális DOM-ot (Virtual DOM) használ, amely gyorsabbá teszi az alkalmazást azáltal, hogy csak a szükséges változtatásokat végzi el a valódi DOM-ban. Tehát nem tölti újra az egész weboldalt, hanem csak azt a a részét amit éppen szükséges.
Szükséges JS ismeretek: modulok használata – import, export, objektumok, ternary operators, arrow functions, spread operators… stb. Ezek nélkül a React használata se fog menni!
Mire lesz szükség hozzá?
Szükség lesz a Node.js telepítésére. Utána a csomagkezelőt már el lehet érni VS Code terminálból, és létre tudjuk hozni az első React alkalmazást az pl: npm create vite@latest paranccsal. Ezután meg fogja kérdezni az alkalmazás nevét, illetve hogy milyen összetevőket szeretnénk. (React, JavaScript). Ha lefutott a script akkor ki fogja írni milyen parancsokat kell még kiadni. cd mappa neve, npm install és npm run dev
Ha minden jól megy ezután elindul a szerver.
Bővebb leírás a telepítésről, és a React komponensekről
Néhány szóban az NPM-ről
- NPM (Node Package Manager) a Node.js hivatalos csomagkezelője, tehát a Node.js telepítésekor az NPM is automatikusan települ.
- Feladata: könyvtárak (package-ek) telepítése, frissítése, verziókezelése és függőségek kezelése.
- Több mint 1 millió nyílt forráskódú csomagot tartalmaz, így a JavaScript ökoszisztéma alapvető része.
- A React maga is egy NPM-csomag.
- A React projektekhez számos további csomag kell (pl.
react-dom, fejlesztői eszközök, build toolok). - Az NPM segítségével egyszerűen telepíthetők és kezelhetők ezek a függőségek.
Node és NPM verzió ellenőrzése terminálból/powershell-ből
|
1 2 |
node -v # Node verzió npm -v # NPM verzió |
React projekt – fontos fájlok és mappák
package.json fájlban:
- dependencies: futtatáshoz szükséges csomagok.
- devDependencies: fejlesztéshez szükséges csomagok.
node_modules: (mappa a projekten belül)
- Ide kerülnek a telepített csomagok.
- Nagyon nagy lehet, de nem kell kézzel módosítani.
package.json:
- A projekt „függőségi listája”.
- Tartalmazza a projekt nevét, verzióját, scriptjeit.
package-lock.json:
- Pontos verziókat rögzít, hogy minden gépen ugyanaz a környezet legyen.
- Automatikusan generálódik telepítéskor.
Miből áll össze a REACT?
Komponensek (React Components): komponensek, ezekből áll össze az alkalmazás. pl. lehet komponens egy fejléc, menü, geléria, stb. Tulajdonképpen a komponens egy JS függvény, aminek van visszatérési értéke. A komponenst úgy lehet meghívni, mint egy html taget.
Funkcionális komponensek (function components): Egyszerűbb, modern megközelítés.Nem kell render metódus, JSX-et adnak vissza. Állapot kezelésre a useState és useEffect hook-ot használja.
Osztályalapú komponensek (class components): Régebbi, de még mindig használt megközelítés.
Egy komponens tartalmazhat HTML-t, CSS-t és JavaScript logikát. A JSX egy olyan szintaktikai kiterjesztés a JavaScripthez, amellyel HTML-szerű kódot írhatunk közvetlenül a JS fájlokban. A böngésző nem érti közvetlenül a JSX-et, ezért a fordító (pl. Vite/Babel) átfordítja azt tiszta JavaScript függvényhívásokká (React.createElement).
JSX: (JavaScript XML): kiegészíti a JS lehetőségeit, egy fájlba lehet JS és html kódot írni, egybe. Fájlkiterjesztése lehet js vagy jsx. A html tageket kisbetűvel kell írni!
Egyetlen gyökérelem: Egy komponens return utasítása csak egyetlen szülő elemet adhat vissza! Ha több elemet akarunk visszaadni, be kell csomagolni őket egy div-be, vagy a modern Reactben használt üres Fragment-be (<> … </>).
|
1 2 3 4 5 6 7 8 |
const Komponens= () => { const nev= "Teszt Elek" return ( <div> {nev} </div> ) } |
Ha csak egy JSX elemet adunk vissza, a return elhagyható, ekkor csak sima zárójelet kell használni!
|
1 2 3 |
const Komponens2 = () => ( <h1>Cím</h1> ); |
Nézzünk még egy példát komponens használatára. Létrehoztam egy gombot tartalmazó komponenst, amit a nevével lehet meghívni .
|
1 2 3 4 5 6 7 8 9 10 11 12 |
function GombKomponens() { return ( <button>Teszt!</button> ); } export default function MyApp() { return ( <div> <h1>Komponens példa</h1> <GombKomponens /> </div> ); |
Mivel a JSX a JavaScripthez tartozik, néhány HTML attribútum nevét meg kellett változtatni, mert ütköznének a JS kulcsszavaival (pl. class, for).
Önzáró tagek: Minden HTML-résznél ben önzáró taget (pl. <img>, <br>, <input>) kötelező lezárni a JSX-ben: <img src="..." />, <br />
A JSX-en belül bármikor visszatérhetünk a JavaScripthez a kapcsos zárójelek ({}) használatával. Bármilyen JS kifejezés használható így (változó, függvényhívás, tömb metódus) .
CSS Inline stílusok a JSX-ben: A sima HTML-es string alapú style="color: red; font-size: 16px;" helyett a JSX-ben a style attribútum egy JavaScript objektumot vár, és a tulajdonságnevek itt is camelCase formátumúak (pl. background-color helyett backgroundColor). Az első {} jelzi, hogy JS-be lépünk, a második {} pedig magát az objektumot jelöli.
|
1 2 3 |
<p style={{ color: 'blue', fontSize: '18px', backgroundColor: '#f0f0f0' }}> Stílusos szöveg </p> |
| HTML formátum | JSX formátum | Miért van rá szükség? / Megjegyzés |
class="box" | className="box" | A class a JavaScriptben egy lefoglalt kulcsszó (osztályok létrehozására szolgál OOP-ban). |
for="email" | htmlFor="email" | A for a JS-ben a for ciklusok kulcsszava. Formoknál a <label> kapcsolására használjuk. |
onclick="..."onchange="..." | onClick={...}onChange={...} | A JSX-ben az eseménykezelők neve camelCase formátumúak, és string helyett JavaScript függvényt ({}) várnak. |
style="color: red;" | style={{ color: 'red' }} | A stílus itt egy JavaScript objektum, a belső kulcsok is camelCase-el íródnak (pl. backgroundColor), és a második {} a JS objektum jelölése. |
tabindex="1" | tabIndex="1" | A több szóból álló attribútumok a JSX-ben egységesen camelCase formátumra váltanak. |
maxlength="50" | maxLength="50" | Ugyancsak camelCase konvenció (colSpan, readOnly, autoFocus stb.). |
<img><br><input> | <img /><br /><input /> | A JSX szigorúbb a HTML-nél: minden önzáró taget kötelező lezárni egy záró perellel (/). |
Feltételes renderelés (Conditional Rendering)
Közvetlenül a JSX-en belül (a {} zárójelek közé) nem írhatunk if utasítást, mert a JSX {} blokkjai csak kifejezéseket (expressions) várnak, az if viszont egy utasítás (statement). Ezért a feltételes renderelést kell használni:
|
1 2 3 4 5 6 |
{/* Feltételes JSX renderelés */} {inStock ? ( <span className="success">Készleten</span> ) : ( <span className="soldout">Elfogyott</span> )} |
Azonban a return előtt lehet használni if-et! Ebben az esetben egy változóba mentjük a kívánt elemet, amit aztán beillesztünk a JSX-be:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function TermekKartya() { // 1. Meghatározzuk az if-fel, hogy mi legyen a tartalom let keszletenVan; if (inStock) { keszletenVan= <span className="success">Készleten</span>; } else { keszletenVan= <span className="outofstock">Elfogyott</span>; } // 2. Beillesztjük a változót a JSX-be return ( <div> {keszletenVan} </div> ); } |
Listák renderelése (.map())
Adattömbök megjelenítéséhez a JavaScript beépített .map() metódusát használjuk. Fontos: Minden generált elemnek kapnia kell egy egyedi key attribútumot (pl. id), hogy a React hatékonyan tudja frissíteni a DOM-ot.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
const fruits = [ { id: 1, name: 'Alma' }, { id: 2, name: 'Körte' }, { id: 3, name: 'Banán' } ]; function FruitList() { return ( <ul> {fruits.map(fruit => ( <li key={fruit.id}>{fruit.name}</li> ))} </ul> ); } |
Import – export
Név szerinti export (Named Export)
Tegyük fel, hogy a products.js fájlból egy products nevű tömböt exportálunk. (./data/products.js):
|
1 |
export const products = [ ... ]; // Név szerinti export |
Hogyan néz ki az import: (ilyenkor kell a kapcsos zárójel!)
|
1 |
import { products } from './data/products'; // Kapcsos zárójel kötelező! |
Alapértelmezett export (Default Export)
Ha a fájl fő eleméről van szó (általában komponenseknél, mint a ProductCard), azt export default-tal jelölik. Ekkor nem kell a kapcsos zárójel, sőt, még a nevet sem kell szigorúan betartanod (bár a konvenció szerint ugyanúgy nevezik).Fájlonként csak egy default export lehet.
Hogyan néz ki az export (./components/ProductCard.jsx):
|
1 |
export default function ProductCard() { ... } // Alapértelmezett export |
Hogyan néz ki az import:
|
1 |
import ProductCard from './components/ProductCard'; // Nincs kapcsos zárójel! |
STATE és PROPS (állapot és paraméterek)
State: A komponens belső állapotát reprezentálja, amely idővel változhat. Az állapot információkat tartalmaz a komponensről, és meghatározza, hogyan viselkedjen a komponens. Az állapot bármikor változhat a felhasználói viselkedés alapján. Az állapot bármilyen változása az egész komponens újra renderelését okozza.
Props (properties): az adatok egyik komponensből a másikba történő átvitelének egyik módja. Úgy tekinthetők, mint a komponenseknek átadott argumentumok. A props csak olvasható, az értékek nem módosíthatóak direkt! Az átadott állapotértékek az állapotfrissítés funkcióval frissíthetők!
Ebben a példában van egy szülő komponens, amiből a nevet és a kort örökli a gyermek komponens.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
function SzuloKomponens() { const nev = "Teszt Elek"; const kor = 30; const fgvKatt = () => { console.log("Gomb megnyomva!") }; return ( <div> <GyermekKomponens nev={nev} kor={kor} fgvKatt={fgvKatt} /> </div> ); } function GyermekKomponens({ nev, kor, fgvKatt }) { return ( <div> <p>Név: {nev}</p> <p>Kor: {kor}</p> <button onClick={fgvKatt}>Kattint rá!</button> </div> ); } |
Egészítsük ki egy state-tel a példát! A useState segítségével tároljuk a klikkelések számát. A példában egy szülőkomponens ad egy nevet (props) a gyermekkomponensnek, amely megjeleníti azt. A gyermek komponens saját állapotot kezel (kattintások számát), és a gomb megnyomásával frissíti ennek értékét.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import React, { useState } from "react"; // Szülőkomponens function SzuloKomponens() { const nev = "Teszt Elek"; return ( <div> <h1>Props és State Példa</h1> <GyermekKomponens nev={nev} /> </div> ); } // Gyermekkomponens function GyermekKomponens({ nev }) { const [szamlalo, setSzamlalo] = useState(0); // State inicializálása const novelSzamlalot = () => { setSzamlalo(szamlalo + 1); // State frissítése }; return ( <div> <p>Név (props): {nev}</p> <p>Kattintások száma (state): {szamlalo}</p> <button onClick={novelSzamlalot}>Kattints!</button> </div> ); } export default SzuloKomponens; |
Hooks
Modern funkciók, amelyek lehetővé teszik az állapotkezelést és egyéb React funkciók használatát funkcionális komponensekben (pl. useState, useEffect).
useState hook példa
A következő példában a useState függvény egy kezdeti értéket kap argumentumként, és egy tömböt ad vissza, amely két elemet tartalmaz: az aktuális állapotot és egy állapotfrissítési függvényt.
Két gombunk van, amelyek növelik és csökkentik a számláló értékét. A gombokra kattintva a számláló állapotát frissítjük. A komponens ezután újra és újra megjeleníti a frissített számlálót.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
const [count, setCount] = useState(0); const increment = () => { setCount(count + 1); }; const decrement = () => { setCount(count - 1); }; return ( <div> <h1>Count: {count}</h1> <button onClick={increment}>Increment</button> <button onClick={decrement}>Decrement</button> </div> ); |
useEffect hook példa: Bővebben: useEffect(setup, dependencies?)
A React useEffect hook egy olyan eszköz, amely lehetővé teszi, hogy a komponensünk „mellék műveleteket” hajtson végre.
- Adatok lekérése egy API-tól: A komponens megjelenésekor vagy frissítésekor adatokat tölthetünk be egy külső forrásból. useEffect-ben használhatjuk az async/await szintaxist
- Subscription-ök kezelése: Feliratkozhatunk bizonyos eseményekre (pl. window resize, timer) és ezekre reagálhatunk a komponensben.
- Direkt DOM manipuláció: Bár általában nem ajánlott, bizonyos esetekben közvetlenül is módosíthatjuk a DOM-ot.
- Tiszta műveletek végrehajtása: Az useEffect segítségével tisztítási műveleteket is végezhetünk, például amikor a komponens le van bontva, vagy amikor bizonyos feltételek teljesülnek.
Az useEffect egy függvényt használ paraméterként. Ez a függvény a függőségi tömbtől függően hívódik meg:
– üres függőségi tömb: a függvény csak egyszer hívódik meg, amikor a komponens megjelenik.
– nem üres függőségi tömb: a függvény minden rendereléskor meghívódik, amikor a függőség tömbben szereplő értékek megváltoznak.
Listázzuk ki az imgflip.com oldalon található képeket! Az api címe: https://api.imgflip.com/get_memes
A lekérés eredménye egy data nevű objektum, ami tartalmaz egy memes nevű tömböt, és minden mém egy objektum a tömbben. A mémek adatai: id, name, url, width, height, box_count, captions.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ "success": true, "data": { "memes": [ { "id": "181913649", "name": "Drake Hotline Bling", "url": "https://i.imgflip.com/30b1gx.jpg", "width": 1200, "height": 1200, "box_count": 2, "captions": 1353750 }, |
Az app.jsx tartalma:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
import React, { useEffect, useState } from 'react'; function App() { const [memes, setMemes] = useState([]); // Állapot a mémek tárolására const [loading, setLoading] = useState(true); // Betöltés állapota const [error, setError] = useState(null); // Hibák tárolása useEffect(() => { const fetchMemes = async () => { try { const response = await fetch('https://api.imgflip.com/get_memes'); // Adatok lekérése const data = await response.json(); if (data.success) { setMemes(data.data.memes); // Mémek beállítása az állapotban } else { throw new Error('Nem sikerült lekérni a mémeket.'); } } catch (err) { setError(err.message); } finally { setLoading(false); } }; fetchMemes(); }, []); // Egyszer fut le, amikor a komponens betöltődik if (loading) return <div>Betöltés...</div>; if (error) return <div>Hiba történt: {error}</div>; return ( <div style={{ padding: '20px' }}> <h1>Mémek listája</h1> <div style={{ display: 'flex', flexWrap: 'wrap', gap: '20px' }}> {memes.map((meme) => ( <div key={meme.id} style={{ width: '200px', textAlign: 'center' }}> <img src={meme.url} alt={meme.name} style={{ maxWidth: '100%', height: 'auto' }} /> <p>{meme.name}</p> </div> ))} </div> </div> ); } export default App; |
Készítsünk mémet! Az imgflip.com oldal api-ját felhasználva, kérdezzük le az összes adatot, tároljuk el egy tömbben! A tömbből válasszunk ki egy képet, és tegyünk rá feliratokat! (2db beviteli mező értékét jelenítjük meg)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
import React, { useEffect, useState } from "react"; import "./App.css"; function OwnMame() { const [meme, setMeme] = useState({ topText: "Jobb ma egy veréb,", bottomText: "mint holnap egy túzok!", imageUrl: "", }); const [memes, setMemes] = useState([]); // Állapot a mémek tárolására const [loading, setLoading] = useState(true); // Betöltés állapota const [error, setError] = useState(null); // Hibák tárolása useEffect(() => { const fetchMemes = async () => { try { const response = await fetch("https://api.imgflip.com/get_memes"); // Adatok lekérése const data = await response.json(); if (data.success) { setMemes(data.data.memes); // Mémek beállítása az állapotban } else { throw new Error("Nem sikerült lekérni a mémeket."); } } catch (err) { setError(err.message); } finally { setLoading(false); } }; fetchMemes(); }, []); // Egyszer fut le, amikor a komponens betöltődik function getMemeImage() { const randomNumber = Math.floor(Math.random() * memes.length); const randomMeme = memes[randomNumber]; setMeme((prevMeme) => ({ ...prevMeme, imageUrl: randomMeme.url, })); } function handleChange(event) { const { name, value } = event.target; setMeme((prevMeme) => ({ ...prevMeme, [name]: value, })); } if (loading) return <div>Betöltés...</div>; if (error) return <div>Hiba történt: {error}</div>; return ( <div className="app-container"> <h1>Mém generátor</h1> <div className="controls"> <input type="text" placeholder="Felső szöveg" name="topText" value={meme.topText} onChange={handleChange} className="text-input" /> <input type="text" placeholder="Alsó szöveg" name="bottomText" value={meme.bottomText} onChange={handleChange} className="text-input" /> <button onClick={getMemeImage} className="generate-button" > Véletlen mém </button> </div> {meme.imageUrl && ( <div className="meme-container"> <img src={meme.imageUrl} alt="Generated Meme" className="meme-image" /> <h2 className="meme-text top">{meme.topText}</h2> <h2 className="meme-text bottom">{meme.bottomText}</h2> </div> )} </div> ); } export default OwnMame; |
Jelenítsük meg a Rick and Morty api segítségével egy szereplő adatait! 1-300 közötti számot adhatunk meg a szövegbetveli mezőben.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
import React, { useEffect, useState } from 'react'; import ReactDOM from 'react-dom/client'; import './App.css'; function Rick() { const [character, setCharacter] = useState(null); const [characterId, setCharacterId] = useState(1); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchCharacter = async () => { setLoading(true); setError(null); try { const response = await fetch(`https://rickandmortyapi.com/api/character/${characterId}`); if (!response.ok) { throw new Error('Network response was not ok'); } const data = await response.json(); setCharacter(data); } catch (error) { setError(error); } finally { setLoading(false); } }; fetchCharacter(); }, [characterId]); const handleInputChange = (event) => { const value = parseInt(event.target.value, 10); if (value >= 1 && value <= 300) { setCharacterId(value); } }; if (loading) { return <div>Loading...</div>; } if (error) { return <div>Error: {error.message}</div>; } return ( <div className="App"> <header className="App-header"> <h1>Rick and Morty Character</h1> </header> <div className="input-container"> <label htmlFor="characterId">Enter Character ID (1-100): </label> <input type="number" id="characterId" value={characterId} onChange={handleInputChange} min="1" max="100" /> </div> {character && ( <div className="character-card"> <img src={character.image} alt={character.name} /> <h2>{character.name}</h2> <p>Status: {character.status}</p> <p>Species: {character.species}</p> <p>Location: {character.location.name}</p> </div> )} </div> ); } |
További példák, és magyarázat a React saját weboldalán.
Frissítve: 2026.11.13.
