frontend elmélet
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,230 @@
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage[magyar]{babel}
|
||||
\usepackage{indentfirst}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{tikz}
|
||||
\usetikzlibrary{positioning}
|
||||
\usepackage{fancyvrb}
|
||||
\usepackage{amssymb}
|
||||
\usepackage{pifont}
|
||||
\usepackage{newunicodechar}
|
||||
|
||||
% Unicode szimbólumok definiálása
|
||||
\newcommand{\cmark}{\ding{51}} % ✓ check mark
|
||||
\newcommand{\xmark}{\ding{55}} % ✗ ballot x
|
||||
\newunicodechar{✓}{\cmark}
|
||||
\newunicodechar{✗}{\xmark}
|
||||
\newunicodechar{❌}{\textcolor{red}{\xmark}}
|
||||
|
||||
% Globális verbatim beállítás - tiny betűméret minden verbatim blokkhoz
|
||||
\fvset{fontsize=\tiny}
|
||||
\usepackage{listingsutf8}
|
||||
\usepackage{textcomp}
|
||||
\usepackage{eurosym}
|
||||
\usepackage{mathtools}
|
||||
\lstset{literate=
|
||||
{á}{{\'a}}1 {é}{{\'e}}1 {í}{{\'i}}1 {ó}{{\'o}}1 {ú}{{\'u}}1
|
||||
{Á}{{\'A}}1 {É}{{\'E}}1 {Í}{{\'I}}1 {Ó}{{\'O}}1 {Ú}{{\'U}}1
|
||||
{à}{{\`a}}1 {è}{{\`e}}1 {ì}{{\`i}}1 {ò}{{\`o}}1 {ù}{{\`u}}1
|
||||
{À}{{\`A}}1 {È}{{\'E}}1 {Ì}{{\`I}}1 {Ò}{{\`O}}1 {Ù}{{\`U}}1
|
||||
{ä}{{\"a}}1 {ë}{{\"e}}1 {ï}{{\"i}}1 {ö}{{\"o}}1 {ü}{{\"u}}1
|
||||
{Ä}{{\"A}}1 {Ë}{{\"E}}1 {Ï}{{\"I}}1 {Ö}{{\"O}}1 {Ü}{{\"U}}1
|
||||
{â}{{\^a}}1 {ê}{{\^e}}1 {î}{{\^i}}1 {ô}{{\^o}}1 {û}{{\^u}}1
|
||||
{Â}{{\^A}}1 {Ê}{{\^E}}1 {Î}{{\^I}}1 {Ô}{{\^O}}1 {Û}{{\^U}}1
|
||||
{œ}{{\oe}}1 {Œ}{{\OE}}1 {æ}{{\ae}}1 {Æ}{{\AE}}1 {ß}{{\ss}}1
|
||||
{ç}{{\c c}}1 {Ç}{{\c C}}1 {ø}{{\o}}1 {å}{{\r a}}1 {Å}{{\r A}}1
|
||||
{€}{{\EUR}}1 {£}{{\pounds}}1 {ő}{{\H{o}}}1 {ű}{{\H{u}}}1
|
||||
}
|
||||
% Docker nyelvdefiníció
|
||||
\lstdefinelanguage{Docker}{
|
||||
keywords={FROM, RUN, CMD, LABEL, MAINTAINER, EXPOSE, ENV, ADD, COPY,
|
||||
ENTRYPOINT, VOLUME, USER, WORKDIR, ARG, ONBUILD, STOPSIGNAL,
|
||||
HEALTHCHECK, SHELL, AS},
|
||||
keywordstyle=\color{blue}\bfseries,
|
||||
identifierstyle=\color{black},
|
||||
sensitive=false,
|
||||
comment=[l]{\#},
|
||||
commentstyle=\color{purple}\ttfamily,
|
||||
stringstyle=\color{red}\ttfamily,
|
||||
morestring=[b]',
|
||||
morestring=[b]"
|
||||
}
|
||||
|
||||
% JavaScript nyelvdefiníció
|
||||
\lstdefinelanguage{JavaScript}{
|
||||
keywords={typeof, new, true, false, catch, function, return, null, catch,
|
||||
switch, var, const, let, if, in, while, do, else, case, break, async,
|
||||
await, class, export, import, extends, super, this, throw, try, default},
|
||||
keywordstyle=\color{blue}\bfseries,
|
||||
ndkeywords={class, export, boolean, throw, implements, import, this},
|
||||
ndkeywordstyle=\color{darkgray}\bfseries,
|
||||
identifierstyle=\color{black},
|
||||
sensitive=false,
|
||||
comment=[l]{//},
|
||||
morecomment=[s]{/*}{*/},
|
||||
commentstyle=\color{purple}\ttfamily,
|
||||
stringstyle=\color{red}\ttfamily,
|
||||
morestring=[b]',
|
||||
morestring=[b]"
|
||||
}
|
||||
|
||||
% YAML nyelvdefiníció
|
||||
\lstdefinelanguage{yaml}{
|
||||
keywords={true,false,null,y,n},
|
||||
keywordstyle=\color{darkgray}\bfseries,
|
||||
sensitive=false,
|
||||
comment=[l]{\#},
|
||||
commentstyle=\color{purple}\ttfamily,
|
||||
stringstyle=\color{red}\ttfamily,
|
||||
morestring=[b]',
|
||||
morestring=[b]",
|
||||
basicstyle=\ttfamily\scriptsize,
|
||||
breaklines=true,
|
||||
columns=fullflexible,
|
||||
keepspaces=true,
|
||||
showstringspaces=false
|
||||
}
|
||||
|
||||
\lstdefinestyle{HTML}{
|
||||
language=HTML,
|
||||
breaklines=true,
|
||||
postbreak=\mbox{\textcolor{red}{$\hookrightarrow$}\space},
|
||||
stringstyle=\ttfamily,
|
||||
inputencoding=utf8,
|
||||
morekeywords={header, time, nav, main, article, section, aside, role,
|
||||
footer, details, open, summary, srcdoc, list, datalist, placeholder,
|
||||
pattern, required, min, max, step, enctype, formaction, formmethod,
|
||||
formnovalidate, formtarget, output}
|
||||
}
|
||||
|
||||
\lstdefinestyle{JavaScript}{
|
||||
basicstyle=\ttfamily\scriptsize,
|
||||
breaklines=true,
|
||||
columns=fullflexible,
|
||||
keepspaces=true,
|
||||
showstringspaces=false,
|
||||
literate={}
|
||||
}
|
||||
\lstdefinestyle{NodeJS}{
|
||||
basicstyle=\ttfamily\scriptsize,
|
||||
breaklines=true,
|
||||
columns=fullflexible,
|
||||
keepspaces=true,
|
||||
showstringspaces=false,
|
||||
literate={}
|
||||
}
|
||||
\lstdefinestyle{Express}{
|
||||
basicstyle=\ttfamily\scriptsize,
|
||||
breaklines=true,
|
||||
columns=fullflexible,
|
||||
keepspaces=true,
|
||||
showstringspaces=false,
|
||||
literate={}
|
||||
}
|
||||
\lstdefinestyle{Prisma}{
|
||||
basicstyle=\ttfamily\scriptsize,
|
||||
breaklines=true,
|
||||
columns=fullflexible,
|
||||
keepspaces=true,
|
||||
showstringspaces=false,
|
||||
literate={}
|
||||
}
|
||||
\usepackage{hyperref}
|
||||
\usepackage{attachfile}
|
||||
\usepackage{multirow}
|
||||
% Navigációs pöttyök hozzáadása subsection nélküli fejezetekhez
|
||||
\usepackage{remreset}
|
||||
\makeatletter
|
||||
\@removefromreset{subsection}{section}
|
||||
\makeatother
|
||||
\setcounter{subsection}{1}
|
||||
%%%%%
|
||||
\attachfilesetup{color={1.0 0.6 0.0},author={MD},description={Kattintson duplán a minta %
|
||||
megtekintéséhez!},icon=Paperclip}
|
||||
% Széchenyi Egyetem arculati színek
|
||||
\definecolor{szenavy}{RGB}{44,62,80} % Sötét kék (fejléc)
|
||||
\definecolor{szecyan}{RGB}{0,168,225} % Világos kék (kiemelés, logó)
|
||||
\definecolor{szezold}{RGB}{139,195,74} % Élénk zöld (akcentus)
|
||||
\definecolor{szeszurke}{RGB}{96,96,96} % Sötét szürke
|
||||
% Kompatibilitás a régi parancsokkal
|
||||
\definecolor{kiemelesszin}{RGB}{0,168,225} % Kék kiemelés (szecyan)
|
||||
\definecolor{kiemelesszinZ}{RGB}{139,195,74} % Zöld kiemelés (szezold)
|
||||
\definecolor{kiemelesszinN}{RGB}{44,62,80} % Navy kiemelés (szenavy)
|
||||
\definecolor{hivatkozasszin}{RGB}{0,168,225} % Kék hivatkozás
|
||||
\newcommand{\kiemel}[1]{{\color{kiemelesszin}#1}}
|
||||
\newcommand{\kiemelZ}[1]{{\color{kiemelesszinZ}#1}}
|
||||
\newcommand{\kiemelN}[1]{{\color{kiemelesszinN}#1}}
|
||||
\newcommand{\hiv}[1]{{\color{hivatkozasszin}#1}}
|
||||
\newcommand{\logoalul}{
|
||||
\begin{picture}(0,0)
|
||||
\put(120,-0){\hbox{\includegraphics[scale=.5]{../common/sze_logo.pdf}}}
|
||||
\put(205,-6){\hbox{\includegraphics[scale=.4]{../common/it_logo.pdf}}}
|
||||
\end{picture}
|
||||
}
|
||||
|
||||
\frenchspacing
|
||||
\usetheme[compress]{Berlin}
|
||||
\useoutertheme[subsection=false]{miniframes}
|
||||
\setbeamerfont{section in head/foot}{size=\tiny}
|
||||
\setbeamerfont{subsection in head/foot}{size=\tiny}
|
||||
|
||||
% Adaptív, kattintható navigáció:
|
||||
% sok section esetén az aktuális marad nagy és szöveges,
|
||||
% a többi section lekicsinyített sorszámként jelenik meg.
|
||||
\newcommand{\sectioncompactthreshold}{11}
|
||||
\makeatletter
|
||||
\providecommand{\totalsectionscount}{0}
|
||||
\AtEndDocument{%
|
||||
\immediate\write\@auxout{\string\gdef\string\totalsectionscount{\arabic{section}}}%
|
||||
}
|
||||
\makeatother
|
||||
|
||||
\setbeamertemplate{section in head/foot}{%
|
||||
{\fontsize{6}{7}\selectfont\bfseries\insertsectionhead}%
|
||||
}
|
||||
\setbeamertemplate{section in head/foot shaded}{%
|
||||
\ifnum\totalsectionscount>\sectioncompactthreshold
|
||||
{\fontsize{4.5}{5.5}\selectfont\insertsectionheadnumber}%
|
||||
\else
|
||||
{\fontsize{5}{6}\selectfont\insertsectionhead}%
|
||||
\fi
|
||||
}
|
||||
\setbeamertemplate{headline}
|
||||
{
|
||||
\leavevmode%
|
||||
\hbox{%
|
||||
\begin{beamercolorbox}[wd=\paperwidth,ht=2.5ex,dp=1.125ex]{section in head/foot}%
|
||||
\insertsectionnavigationhorizontal{\paperwidth}{}{\hskip0pt plus1filll}
|
||||
\end{beamercolorbox}%
|
||||
}
|
||||
\vskip0pt%
|
||||
}
|
||||
|
||||
% Kisebb betűméret a slide-okhoz
|
||||
\setbeamerfont{frametitle}{size=\normalsize}
|
||||
\setbeamerfont{framesubtitle}{size=\small}
|
||||
\setbeamerfont{block title}{size=\small}
|
||||
\setbeamerfont{block body}{size=\footnotesize}
|
||||
\setbeamerfont{itemize/enumerate body}{size=\footnotesize}
|
||||
\setbeamerfont{itemize/enumerate subbody}{size=\scriptsize}
|
||||
|
||||
% Beamer színséma testreszabása Széchenyi arculathoz
|
||||
\setbeamercolor{structure}{fg=szecyan}
|
||||
\setbeamercolor{palette primary}{bg=szenavy,fg=white}
|
||||
\setbeamercolor{palette secondary}{bg=szecyan,fg=white}
|
||||
\setbeamercolor{palette tertiary}{bg=szezold,fg=white}
|
||||
\setbeamercolor{palette quaternary}{bg=szeszurke,fg=white}
|
||||
\setbeamercolor{titlelike}{parent=palette primary}
|
||||
\setbeamercolor{frametitle}{bg=szenavy,fg=white}
|
||||
\setbeamercolor{frametitle right}{bg=szenavy}
|
||||
\setbeamercolor{block title}{bg=szecyan,fg=white}
|
||||
\setbeamercolor{block body}{bg=szecyan!10,fg=black}
|
||||
\setbeamercolor{block title alerted}{bg=szezold,fg=white}
|
||||
\setbeamercolor{block body alerted}{bg=szezold!10,fg=black}
|
||||
\setbeamercolor{item}{fg=szecyan}
|
||||
\setbeamercolor{subitem}{fg=szezold}
|
||||
|
||||
\author{Magda Donát}
|
||||
\institute{Széchenyi István Egyetem, Győr}
|
||||
\date{\hiv{\href{https://git.mdnd-it.cc/Donat/GKNB_MSTM071}{https://git.mdnd-it.cc/Donat/GKNB_MSTM071}}\\ \today}
|
||||
@@ -0,0 +1,37 @@
|
||||
\section{Adatlekérés}
|
||||
|
||||
\begin{frame}{Hogyan kap adatot egy React alkalmazás?}
|
||||
\begin{block}{Az alaphelyzet}
|
||||
A React alkalmazás a böngészőben fut --- az adatok (felhasználók, termékek, stb.) általában egy \textbf{háttérszerveren} élnek. Az adatcserét HTTP kérésekkel végezzük: a frontend elküldi a kérést, a szerver JSON formátumban válaszol.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item A böngésző beépített \texttt{fetch} API-ját vagy az \textbf{Axios} könyvtárat használhatjuk.
|
||||
\item Az adatlekérést általában egy \texttt{useEffect}-ben indítjuk el --- amikor a komponens megjelenik.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Fetch vs.\ Axios}
|
||||
\begin{itemize}
|
||||
\item \textbf{Fetch:} beépített, nem kell telepíteni. Hátránya: a hibás HTTP kódokat (pl. 404) \emph{nem} dobja el automatikusan, JSON-t kézzel kell kezelni.
|
||||
\item \textbf{Axios:} telepíthető könyvtár. Automatikusan kezeli a JSON-t, a HTTP hibákra kivételt dob, és \textbf{interceptorokkal} (pl. token hozzáadása minden kéréshez) könnyű kiegészíteni.
|
||||
\item Nagyobb projekteknél az Axios általában kényelmesebb és biztonságosabb.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Állapotok az adatlekérés során}
|
||||
\begin{itemize}
|
||||
\item \textbf{Betöltés (loading):} amíg a kérés folyamatban van, mutassunk spinner-t vagy skeleton-t --- ne maradjon üres az oldal.
|
||||
\item \textbf{Siker:} megérkeztek az adatok, megjelenítjük.
|
||||
\item \textbf{Hiba (error):} a hálózat megszakadt, a szerver hibát adott --- barátságos hibaüzenetet mutassunk, ne csak üres felületet.
|
||||
\item \textbf{Üres állapot (empty):} a válasz sikeres, de nincs adat --- pl. "Nincsenek még termékek".
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Szerverállapot-kezelés: TanStack Query}
|
||||
\begin{itemize}
|
||||
\item Manuálisan kezelni a loading/error/data állapotokat minden komponensben ismétlődő és hibalehetőséges.
|
||||
\item A \textbf{TanStack Query} (korábbi nevén React Query) ezt automatizálja: cache-eli az adatokat, háttérben frissíti, kezeli az újrapróbálkozást.
|
||||
\item \textbf{Optimista frissítés:} azonnal frissítjük a UI-t a szerver válasza előtt --- ha a szerver hibát ad, visszaállítjuk. Így az alkalmazás gyorsabbnak tűnik.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
@@ -0,0 +1,38 @@
|
||||
\section{Build \& Deploy}
|
||||
|
||||
\begin{frame}{Mi történik a build folyamatban?}
|
||||
\begin{block}{Build = el�'készítés az éles kiadásra}
|
||||
Fejlesztés közben a kód sokszor nem optimális formában van --- sok fájl, olvasható változónevek, fejlesztői segédletek. A build folyamat ezeket átalakítja böngészőbarát, gyors formára.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item \textbf{Minifikálás:} felesleges szóközök, kommentek eltávolítása, változónevek rövidítése --- kisebb fájlméret.
|
||||
\item \textbf{Tree-shaking:} a nem használt kód kiszűrése a végleges csomagból.
|
||||
\item \textbf{Kódfelosztás:} az alkalmazás több kisebb fájlra bontva töltődik --- csak ami kell, töltődik le.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Környezeti változók}
|
||||
\begin{itemize}
|
||||
\item Az alkalmazásnak fejlesztési és éles környezetben más beállításokra van szüksége (API URL, kulcsok stb.).
|
||||
\item Ezeket \textbf{.env fájlokban} tároljuk --- a \texttt{.env.local} soha nem kerül Git-be (érzékeny adatok).
|
||||
\item Vite-ban a \texttt{VITE\_} előtagú változók kerülnek a kliensoldali kódba --- a többi csak szerveroldalon érhető el.
|
||||
\item \textbf{Figyelem:} titkos kulcsokat soha ne tegyük a kliensoldali kódba --- bárki láthatja!
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Deploy lehet�'ségek}
|
||||
\begin{itemize}
|
||||
\item \textbf{Vercel, Netlify:} egy Git push-ra automatikusan deployol, ingyen elérhető próbaprojektekhez --- a legegyszerűbb indulás.
|
||||
\item \textbf{GitHub Pages:} statikus oldalakhoz, nyílt forráskódú projektekhez kényelmes.
|
||||
\item \textbf{Saját szerver / CDN:} Nginx-szel statikus fájlokat tálalunk; fontos az SPA fallback beállítása (minden URL-t az \texttt{index.html}-re irányítunk, a React Router veszi át).
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Biztonsági alapok}
|
||||
\begin{itemize}
|
||||
\item \textbf{XSS (Cross-Site Scripting) elleni védelem:} a React alapból escape-eli a JSX-ben megjelenített szövegeket --- a \texttt{dangerouslySetInnerHTML} viszont kikerüli ezt, csak tisztított adattal szabad használni.
|
||||
\item \textbf{Auth token kezelés:} a JWT-t ne \texttt{localStorage}-ban tároljuk --- JavaScript elérheti. HTTP-only cookie biztonságosabb, mert JavaScriptből nem olvasható.
|
||||
\item \textbf{Hibamonitorozás:} éles alkalmazásban szükséges eszköz (pl. Sentry), hogy a felhasználóknál fellépő hibákról értesüljünk.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
@@ -0,0 +1,53 @@
|
||||
\section{Komponensek}
|
||||
|
||||
\begin{frame}{Mi az a komponens?}
|
||||
\begin{block}{Analógia: LEGO kockák}
|
||||
Képzeljük el, hogy a weboldalunk LEGO-ból épül. Minden egyes „kocka" egy önálló, újrafelhasználható egység --- ezt nevezzük \textbf{komponensnek}.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item Egy komponens egy JavaScript \textbf{függvény}, amely JSX-et ad vissza --- leírja, mit jelenítsen meg.
|
||||
\item A teljes oldal komponensek fájából áll: van egy gyökér (\texttt{App}), abból nőnek ki az alkomponensek.
|
||||
\item Például: \texttt{<Header />}, \texttt{<ProductList />}, \texttt{<Footer />} --- mindegyik egy-egy felelősségi kör.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Funkcionális és osztály alapú komponensek}
|
||||
\begin{itemize}
|
||||
\item \textbf{Funkcionális komponens (modern):} egyszerű JavaScript függvény, hookok segítségével kezeli az állapotot. Ez az ajánlott forma.
|
||||
\item \textbf{Osztály alapú komponens (régebbi):} ES6 osztályból örököl, életciklus-metódusokat használ. Ma már nem szükséges új kódban alkalmazni.
|
||||
\item A React csapat 2019 óta a funkcionális megközelítést javasolja --- rövidebb, könnyebben tesztelhető.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Mi az a prop?}
|
||||
\begin{block}{Analógia: paraméterek}
|
||||
Ahogy egy függvénynek paramétereket adhatunk, a komponenseknek is adhatunk adatokat kívülről. Ezeket \textbf{props}-nak (properties --- tulajdonságok) hívjuk.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item A props \textbf{csak olvasható}: a komponens nem módosíthatja a kapott értéket.
|
||||
\item Props segítségével ugyanaz a komponens különböző tartalommal jeleníthető meg --- ez teszi újrafelhasználhatóvá.
|
||||
\item Szinte bármilyen érték átadható: szöveg, szám, tömb, függvény, sőt más komponens is.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{A \texttt{children} prop és a kompozíció}
|
||||
\begin{itemize}
|
||||
\item A \texttt{children} egy speciális prop: a komponens nyitó- és zárócímkéje \emph{közé} írt tartalmat jelenti.
|
||||
\item Például egy \texttt{<Modal>} komponens bármilyen tartalmat fogadhat belülről --- nem kell előre tudni, mi lesz benne.
|
||||
\item Ez a \textbf{kompozíció} alapelve: összetett UI-t kisebb, általános darabokból rakunk össze öröklés helyett.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Kulcsok (\texttt{key}) listáknál}
|
||||
\begin{block}{Miért kell a \texttt{key}?}
|
||||
Ha React egy listát renderel, azonosítania kell, melyik elemet kell frissíteni, törölni vagy hozzáadni. A \texttt{key} prop ebben segít --- egyedi azonosítóként szolgál.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item A \texttt{key} értéke legyen \textbf{stabil és egyedi} --- tipikusan az adatbázisból érkező ID.
|
||||
\item A tömb indexét csak akkor használjuk, ha a lista soha nem változik sorrendben.
|
||||
\item Hiányzó vagy nem egyedi \texttt{key} esetén React figyelmeztetést dob, és hibás frissítések léphetnek fel.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
@@ -0,0 +1,133 @@
|
||||
\section{Context}
|
||||
|
||||
\begin{frame}{A prop drilling probléma}
|
||||
\begin{block}{Mi az a prop drilling?}
|
||||
Ha egy adat a komponensfa tetején él, de csak mélyen lent lévő komponensnek kell, akkor az összes közbülső komponensen át kell „ütni" props-szal --- még akkor is, ha a köztes komponensek maguk nem használják. Ez nehézkessé és törékennyé teszi a kódot.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
A \textbf{Context API} ezt a problémát oldja meg: az adatot egy közös „kút"-ban tároljuk, amelyből bármely leszármazott komponens közvetlen props nélkül is ihat.
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Mire jó a Context API?}
|
||||
\begin{itemize}
|
||||
\item \textbf{Ritkán változó, globális adatok} átadásához ideális --- pl. téma (dark/light), aktív nyelv, bejelentkezett felhasználó adatai.
|
||||
\item Két lépés: 1) \textbf{Provider} --- közzéteszi az értéket a fában; 2) \textbf{useContext} --- olvasásra foglalja le a komponensben.
|
||||
\item Nem teljes értékű állapotkezelő: sűrűn változó adatokhoz ne használjuk, mert minden fogyasztó komponens újrarenderelődik.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{A Context és a Provider szerepe}
|
||||
\begin{block}{Context}
|
||||
A \texttt{createContext} egy konténer, amely az adatot tárolja. Maga nem csinál semmit --- csak definiálja, hogy melyik adat lesz megosztva.
|
||||
\end{block}
|
||||
\vspace{0.4em}
|
||||
\begin{block}{Provider}
|
||||
A \texttt{Provider} egy komponens, amely körülvesz más komponenseket, és az értéket \textbf{elérhetővé teszi} számukra. Minden komponens, amely a Provider-ben van, felhasználhatja az adatot.
|
||||
\end{block}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}[fragile]{Context és Provider --- alapvető kódpélda}
|
||||
\begin{verbatim}
|
||||
import { createContext, useContext } from "react";
|
||||
|
||||
// 1. Context létrehozása
|
||||
const ThemeContext = createContext("light");
|
||||
|
||||
// 2. Provider komponens a legfelső szinten
|
||||
function App() {
|
||||
return (
|
||||
<ThemeContext.Provider value="dark">
|
||||
<Header />
|
||||
<Content />
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
}
|
||||
\end{verbatim}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}[fragile]{Context és Provider --- alapvető kódpélda folytatás}
|
||||
\begin{verbatim}
|
||||
// 3. Leszármazott komponensben: useContext
|
||||
function Header() {
|
||||
const theme = useContext(ThemeContext);
|
||||
return <h1>Tema: {theme}</h1>;
|
||||
}
|
||||
\end{verbatim}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}[fragile]{Állapottal rendelkező Context --- teljesebb példa}
|
||||
\footnotesize\begin{verbatim}
|
||||
// ThemeContext.js
|
||||
const ThemeContext = createContext();
|
||||
|
||||
export function ThemeProvider({ children }) {
|
||||
const [theme, setTheme] = useState("light");
|
||||
|
||||
return (
|
||||
<ThemeContext.Provider value={{ theme, setTheme }}>
|
||||
{children}
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useTheme() {
|
||||
return useContext(ThemeContext);
|
||||
}
|
||||
\end{verbatim}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}[fragile]{Felhasználás az alkalmazásban}
|
||||
\begin{verbatim}
|
||||
// App.js
|
||||
import { ThemeProvider } from "./ThemeContext";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<ThemeProvider>
|
||||
<Header />
|
||||
<MainContent />
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
\end{verbatim}
|
||||
\end{frame}
|
||||
\begin{frame}[fragile]{Felhasználás az alkalmazásban folytatás}
|
||||
\begin{verbatim}
|
||||
// Header.js
|
||||
function Header() {
|
||||
const { theme, setTheme } = useTheme();
|
||||
return (
|
||||
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
|
||||
Aktualis tema: {theme}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
\end{verbatim}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Hogyan működik a gyakorlatban?}
|
||||
\begin{itemize}
|
||||
\item \texttt{createContext()} a kontextus objektumot hozza létre.
|
||||
\item A \texttt{Provider} értéket ad át a \texttt{value} prop-on.
|
||||
\item Mélyen lent elhelyezkedő komponensek a \texttt{useContext()} hookkal használják az adatot.
|
||||
\item Custom hook (pl. \texttt{useTheme()}) felhasználóbarátabb API-t nyújt.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Jó gyakorlatok és gyakori hibák}
|
||||
\begin{itemize}
|
||||
\item \textbf{Custom hook:} szokjunk meg a saját hook megírásának (pl. \texttt{useTheme}), ez takarítja a kódot és segíti az újrafelhasználást.
|
||||
\item \textbf{Túl nagy Context:} ha túl sok adat van egy Context-ben, minden frissítés újrarendereli az összes fogyasztót --- inkább bontsuk fel több kisebb Context-re.
|
||||
\item \textbf{nem Context-ben való adat:} gyorsan változó, nagy mennyiségű adat (pl. valós idejű pozíciók) nem Context-ben való --- inkább store (Redux, Zustand) vagy külön state.
|
||||
\item \textbf{Default érték:} adjunk adjunk értelmes \texttt{createContext()} paraméterét --- dev módban segít descobrire a hiányzó Providert.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Context vs. más megoldások}
|
||||
\begin{itemize}
|
||||
\item \textbf{Props:} egyszerű, néhány szintű adatátadásra. Érthető, explicit.
|
||||
\item \textbf{Context:} ritkán változó, globális adatok. Szétszórt komponensek között.
|
||||
\item \textbf{State Manager (Redux/Zustand):} komplett üzleti logika, komplex frissítések, szinkronizálás.
|
||||
\item \textbf{Szerverállapot (TanStack Query):} API-ból érkező adatok, cache, szinkronizálás.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
@@ -0,0 +1,43 @@
|
||||
\section{Mellékhatások}
|
||||
|
||||
\begin{frame}{Mi az a mellékhatás (side effect)?}
|
||||
\begin{block}{Definíció}
|
||||
Mellékhatásnak nevezzük mindazt, ami a komponens \textbf{renderelésén kívül} történik: hálózati kérés, DOM-módosítás, timer beállítása, eseménykezelő regisztrálása.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item A renderelési fázisban ilyen műveletek nem végzhetők --- a React elvárja, hogy a renderelés \textbf{tiszta} (mellékhatásmentes) legyen.
|
||||
\item A \texttt{useEffect} hook nyújtja a lehetőséget arra, hogy e műveleteket \emph{renderelés után} hajtsuk végreh.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{\texttt{useEffect} --- mikor és hányszor fut le?}
|
||||
\begin{itemize}
|
||||
\item \textbf{Függőségi történk:} minden egyes renderelés után lefut --- általában nem ezt akarjuk.
|
||||
\item \textbf{Üres történk (\texttt{[]}):} csak az első megjelenítéskor fut le egyszer --- pl. induló adatlekéréshez.
|
||||
\item \textbf{Értékekkel (\texttt{[id, szuro]}):} amikor a felsorolt értékek bármelyike megváltozik, újra lefut.
|
||||
\end{itemize}
|
||||
\vspace{0.4em}
|
||||
A függőségi történk tehát azt szabályozza, \textbf{mikor} akarjuk az effektet ismét futtatni.
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Cleanup --- takarítás az effect után}
|
||||
\begin{block}{Miért kell cleanup?}
|
||||
Ha egy komponens eltűnik az oldalról (pl. navigáció közben), az esetlegesen elindított timerek, eseményfigyelők tovább futnak, memóriaszivárgást okozva. A cleanup függvény ezt akadályozza meg.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item Az effect \textbf{visszaadhat egy cleanup függvényt}: ez fut le a komponens unmountjakor, illetve az effect következő lefutása előtt.
|
||||
\item Tipikus eset: \texttt{clearInterval}, \texttt{removeEventListener}, API kérés megszakítása (\texttt{AbortController}).
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Leggyakoribb hibák \texttt{useEffect}-tel}
|
||||
\begin{alertblock}{Figyelem}
|
||||
\begin{itemize}
|
||||
\item \textbf{Hiányzó dependency:} ha egy változót használunk de nem szerepel a tömbben, a hook régi értékkel dolgozhat --- ez nehezen felderíthető hiba.
|
||||
\item \textbf{Végtelen ciklus:} ha az effect frissít egy állapotot, ami maga is dependency, kör forgás indul.
|
||||
\item \textbf{Túl sok logika egy effectben:} egy effect egy felelősséget kezeljen; ha kettőt kezelne, bontsuk szét.
|
||||
\end{itemize}
|
||||
\end{alertblock}
|
||||
\end{frame}
|
||||
@@ -0,0 +1,38 @@
|
||||
\section{Űrlapkezelés}
|
||||
|
||||
\begin{frame}{Kontrollált és nem kontrollált input}
|
||||
\begin{block}{Kontrollált input}
|
||||
Az input mező értékét a React állapot tárolja és vezérli. A \texttt{value} prop és az \texttt{onChange} esemény mindig szinkronban tartja a React állapotot és a mezőt --- bármikor pontosan tudjuk, mi van a mezőben.
|
||||
\end{block}
|
||||
\vspace{0.3em}
|
||||
\begin{block}{Nem kontrollált input}
|
||||
A DOM maga kezeli az értéket --- React csak beküldéskor kéri le (\texttt{useRef}-fel). Egyszerűbb felépítés, de valós idejű validáció nehezebb.
|
||||
\end{block}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Miért érdemes kontrollált inputot használni?}
|
||||
\begin{itemize}
|
||||
\item Mindig pontos képünk van az aktuális beviteli értékről --- nem kell a DOM-ból "kiolvasni".
|
||||
\item \textbf{Valós idejű validáció:} hibát jelzünk gépelés közben, nem csak beküldéskor.
|
||||
\item Feltételes engedélyezés/tiltás, formázás, karakterlimit könnyen kezelhető.
|
||||
\item Hátránya: sok mezőnél sok state szükséges --- erre nyújtanak megoldást a könyvtárak.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Validáció --- mit kell ellenőrizni?}
|
||||
\begin{itemize}
|
||||
\item \textbf{Kötelező mezők:} ne lehessen üres beküldés.
|
||||
\item \textbf{Formátum:} email, telefonszám, irányítószám megfelelő-e?
|
||||
\item \textbf{Üzleti szabályok:} min. 8 karakteres jelszó, egyező jelszavak, stb.
|
||||
\item A hibákat erős vizuális visszajelzéssel kell jelezni --- a felhasználó ne találgasson, mi a baj.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Miért használjunk könyvtárat?}
|
||||
\begin{itemize}
|
||||
\item Kézi megvalósításnál sok ismétl�'d�' kód keletkezik --- minden mez�'höz saját state, validáció, hibaüzenet.
|
||||
\item \textbf{React Hook Form:} minimális újrarenderelés, nagyon gyors, könnyen tanulható API --- a legtöbb esetben ez az ajánlott.
|
||||
\item \textbf{Formik:} régebben nagyon népszerű, sok csapat már ismeri; kicsit több boilerplate.
|
||||
\item \textbf{Zod / Yup:} séma alapú validáló könyvtárak --- a validációs logikát típusbiztos sémában írjuk le, React Hook Form-mal jól kombinálható.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
@@ -0,0 +1,55 @@
|
||||
\section{Hookok}
|
||||
|
||||
\begin{frame}{Mi az a Hook?}
|
||||
\begin{block}{Az alapgondolat}
|
||||
A React 16.8 előtt az állapotkezelés és életciklus-logika csak osztály alapú komponensekben volt lehetséges. A hookok ezt hozták el \textbf{funkcionális komponensekbe} is --- így ma már egyszerűbb szintaxissal írhatunk komplex viselkedést.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item A hook neve mindig \texttt{use}-szal kezdődik (pl. \texttt{useState}, \texttt{useEffect}).
|
||||
\item Beépített hookok lefedik a leggyakoribb igényeket: állapot, mellékhatás, kontextus, optimalizálás.
|
||||
\item \textbf{Custom hook:} saját logikát csomagolhatunk újrafelhasználható hookba --- pl. \texttt{useWindowSize}, \texttt{useAuth}.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{\texttt{useState} --- az alapvető állapot hook}
|
||||
\begin{block}{Mit csinál?}
|
||||
Az \texttt{useState} lehetővé teszi, hogy egy komponens \textbf{emlékezzen} valamire a renderelések között --- pl. egy számláló értékére, egy modal nyitott/zárt állapotára.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item Visszaad egy értéket és egy \textbf{szetter függvényt}: \texttt{const [ertek, setErtek] = useState(kezdoErtek)}.
|
||||
\item Ha a szetter meghívódik, a React \textbf{újrarendereli} a komponenst az új értékkel.
|
||||
\item A kezdeti érték csak az első renderelésnél számít --- utána React maga kezeli.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{\texttt{useReducer} --- összetettebb állapothoz}
|
||||
\begin{itemize}
|
||||
\item Ha az állapot több összefüggő értékből áll, vagy a frissítési logika bonyolult, \texttt{useReducer} jobb választás lehet.
|
||||
\item Működése hasonló a Redux elvéhez: van egy \textbf{akció} (mi történt) és egy \textbf{reducer} függvény (hogyan változik az állapot).
|
||||
\item A frissítési logika egy helyen, a reducerben él --- olvashatóbb, tesztelhető.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{\texttt{useRef} --- referencia DOM elemre vagy értékre}
|
||||
\begin{itemize}
|
||||
\item Az \texttt{useRef} olyan értéket tárol, amely \textbf{nem vált ki újrarenderelést} megváltozásakor.
|
||||
\item Leggyakoribb használat: közvetlen DOM-elem elérése --- pl. input fókuszálása, video lejátszás indítása.
|
||||
\item Hasznos timer ID-k és előző értékek tárolására is: bármire, amit renderelések között „el akarunk menteni" anélkül, hogy az oldal frissüljön.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Hook szabályok --- miért fontosak?}
|
||||
\begin{alertblock}{Alapszabályok}
|
||||
\begin{enumerate}
|
||||
\item Hookot csak \textbf{komponens vagy custom hook legfelső szintjén} hívjunk.
|
||||
\item Ne ciklusban, feltételben vagy beágyazott függvényen belül hívjuk.
|
||||
\end{enumerate}
|
||||
\end{alertblock}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item \textbf{Miért?} A React a hookok \emph{hívási sorrendje} alapján párosítja az állapotokat a komponenshez. Ha a sorrend változik (pl. feltétel miatt kimarad egy hook), React összetéveszti, melyik állapot melyikhez tartozik.
|
||||
\item Az ESLint \texttt{eslint-plugin-react-hooks} csomag automatikusan ellenőrzi ezeket.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
@@ -0,0 +1,37 @@
|
||||
\section{Könyvtárak}
|
||||
|
||||
\begin{frame}{UI komponens könyvtárak}
|
||||
\begin{block}{Mire valók?}
|
||||
Kész, előre megírt és stílusozott UI komponensek gyűjteményei --- gombok, táblázatok, modalok, értesítések stb. Nem kell nulláról megírni a vizuális elemeket.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item \textbf{MUI (Material UI):} Google Material Design stílus, nagyon széleskörű komponenskészlet.
|
||||
\item \textbf{Headless UI, Radix UI:} csak a viselkedési logikát adják, a megjelenést teljes egészében mi írjuk --- maximális szabadság, Tailwind-del kombinálható.
|
||||
\item \textbf{shadcn/ui:} Radix + Tailwind alapú, másolható komponensek --- egyre népszerűbb.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Állapot és adatkezelés ökoszisztéma}
|
||||
\begin{itemize}
|
||||
\item \textbf{Redux Toolkit:} a Redux modern, kevésbé terjengős változata. Komplex állapotlogikához és nagy csapatoknak ideális.
|
||||
\item \textbf{Zustand:} egyszerű, minimális API-jú globális store. Kis és közepes projekteknél kiváló alternatíva.
|
||||
\item \textbf{Jotai:} atomi állapotkezelés --- az állapot apró, egymásra épülő atomokból áll. Fine-grained reaktivitáshoz jó.
|
||||
\item \textbf{TanStack Query:} szerverállapot kezelésére specializált --- cache, háttérfrissítés, újrapróbálkozás.
|
||||
\item \textbf{Zod:} típusbiztos adatvalidáció sémákkal --- API válaszok, form adatok ellenőrzéséhez.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Összefoglalás --- a React ökoszisztéma}
|
||||
\begin{itemize}
|
||||
\item \textbf{Alap:} komponensek, props, state, hookok, JSX.
|
||||
\item \textbf{Interakció:} eseménykezelés, űrlapok, navigáció.
|
||||
\item \textbf{Adatok:} useEffect, Axios / TanStack Query, Context.
|
||||
\item \textbf{Minőség:} TypeScript, tesztelés, teljesítmény.
|
||||
\item \textbf{Kiadás:} build, deploy, biztonság, monitorozás.
|
||||
\end{itemize}
|
||||
\vspace{0.5em}
|
||||
\begin{alertblock}{Tanács kezdőknek}
|
||||
Ne akarjuk egyszerre megtanulni az összes eszközt. Kezdjük az alapokkal (komponens, state, effect), és szükség szerint bővítsük a tudást.
|
||||
\end{alertblock}
|
||||
\end{frame}
|
||||
@@ -0,0 +1,36 @@
|
||||
\section{Teljesítmény}
|
||||
|
||||
\begin{frame}{Mi az az újrarenderelés?}
|
||||
\begin{block}{Az alapjelenség}
|
||||
Amikor egy komponens állapota vagy props-a megváltozik, a React \textbf{újrarendereli} azt a komponenst --- és alapértelmezetten az összes gyermekét is. Ez legtöbbször tökéletesen gyors. Nagy és mély fáknál azonban szükségtelen újrarenderelések lassíthatnak.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
Fontos szabály: \textbf{mérjünk, aztán optimalizáljunk!} Ne alkalmazzunk előre memoizációt ott, ahol valójában nincs probléma.
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{React DevTools Profiler}
|
||||
\begin{itemize}
|
||||
\item A React DevTools böngésző-bővítmény beépített \textbf{Profiler} lapján látjuk, hogy melyik komponens hányszor és mennyi ideig rendereledett.
|
||||
\item Felvesszük egy interakció közben a renderelési folyamatot, majd azonosítjuk a lassú vagy felesleges részeket.
|
||||
\item Csak azután nyúljunk optimalizáláshoz, ha a profiler valódi problémát mutat.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Memoizáció --- mit és mikor?}
|
||||
\begin{itemize}
|
||||
\item \textbf{React.memo:} ha egy komponens props-ai nem változnak, ne renderelje újra. Érdemes drága megjelenítésű, sokszor hívott komponenseken alkalmazni.
|
||||
\item \textbf{useMemo:} ha egy számítás nagyon drága (pl. óriási lista szűrése), cache-eljük az eredményt --- csak akkor számítsuk újra, ha a bemenetek megváltoztak.
|
||||
\item \textbf{useCallback:} ha egy függvényt props-ként adunk át, és fontos, hogy a referenciája stabil maradjon (pl. React.memo-val védett gyermeknek).
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Kódfelosztás és lusta betöltés}
|
||||
\begin{block}{A probléma}
|
||||
Nagy alkalmazásoknál a teljes JavaScript csomag egyszerre töltődik be --- ez lassítja az első megjelenést.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item \textbf{React.lazy + Suspense:} az egyes oldalakat/modulokat csak akkor töltjük be, amikor a felhasználó ténylegesen odanavigál.
|
||||
\item \textbf{Lista virtualizáció} (pl. \texttt{react-window}): ha több ezer listaelemet kell megjeleníteni, csak a látható elemeket rendereljük --- a többi DOM-ban sem szerepel.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
@@ -0,0 +1,80 @@
|
||||
\section{React alapok}
|
||||
|
||||
\begin{frame}{Mi a React?}
|
||||
\begin{block}{Rövid definíció}
|
||||
A React egy nyílt forráskódú JavaScript \textbf{könyvtár}, amelyet a Meta (Facebook) fejlesztett ki.
|
||||
Fő célja: webalkalmazások felhasználói felületének (UI) hatékony és karbantartható megírása.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item Nem egy teljes keretrendszer --- csak a megjelenítési réteggel foglalkozik.
|
||||
\item Kiegészítő könyvtárakkal (routing, adatkezelés) teljes alkalmazás is építhető.
|
||||
\item 2013 óta aktívan fejlesztik; ma az egyik legelterjedtebb frontend technológia.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Deklaratív vs.\ imperatív szemlélet}
|
||||
\begin{columns}
|
||||
\column{0.48\textwidth}
|
||||
\textbf{Régi, imperatív szemlélet}\\
|
||||
\textit{„Keresd meg a gombot, módosítsd a szövegét, frissítsd a listát\ldots"}\\
|
||||
\vspace{0.5em}
|
||||
$\Rightarrow$ Megadjuk, \emph{hogyan} csinálja a böngésző lépésről lépésre.
|
||||
|
||||
\column{0.48\textwidth}
|
||||
\textbf{React: deklaratív szemlélet}\\
|
||||
\textit{„Ha a kosár üres, ezt jelenítsd meg; ha van termék, amazt."}\\
|
||||
\vspace{0.5em}
|
||||
$\Rightarrow$ Megadjuk, \emph{mit} akarunk látni --- a React intézi a DOM-frissítést.
|
||||
\end{columns}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Mi az a virtuális DOM?}
|
||||
\begin{block}{DOM = Document Object Model}
|
||||
A böngésző az oldalt egy faszerkezetben (DOM) tárolja. Sok elem esetén a közvetlen DOM-módosítás lassú lehet.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item A React egy \textbf{virtuális DOM}-ot tart fenn a memóriában --- ez egy gyors, könnyű másolata a valódi DOM-nak.
|
||||
\item Állapotváltozáskor összehasonlítja az új és a régi virtuális DOM-ot (\emph{diffing}).
|
||||
\item Csak a ténylegesen megváltozott részeket frissíti a böngészőben --- ezért gyors és hatékony.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Miért érdemes React-et tanulni?}
|
||||
\begin{itemize}
|
||||
\item \textbf{Újrafelhasználhatóság:} egyszer megírt komponens bárhová beilleszthető.
|
||||
\item \textbf{Nagy közösség:} rengeteg oktatóanyag, könyvtár és álláshirdetés.
|
||||
\item \textbf{Skálázhatóság:} kis projekttől nagy vállalati alkalmazásig alkalmazható.
|
||||
\item \textbf{Átváltható tudás:} React Native-szal mobilalkalmazás is írható ugyanezzel a szemlélettel.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}[fragile]{Projektindítás Vite-tal}
|
||||
\begin{block}{Miért Vite?}
|
||||
A Vite egy modern build eszköz: gyorsan indítja el a fejlesztői szervert, és azonnal tükrözi a módosításokat a böngészőben. Ezt hívják HMR-nek (Hot Module Replacement --- „élő újratöltés").
|
||||
\end{block}
|
||||
\begin{verbatim}
|
||||
npm create vite@latest sajat-app -- --template react
|
||||
cd sajat-app
|
||||
npm install
|
||||
npm run dev
|
||||
\end{verbatim}
|
||||
\begin{itemize}
|
||||
\item Az \texttt{npm run dev} elindítja a fejlesztői szervert (alapból \texttt{localhost:5173}).
|
||||
\item \texttt{npm run build} paranccsal production-kész, tömörített kódot kapunk.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{JSX --- HTML és JavaScript egyben}
|
||||
\begin{block}{Mi az a JSX?}
|
||||
A JSX (JavaScript XML) egy szintaktikai kiterjesztés: HTML-szerű kódot írhatunk JavaScript-ben.
|
||||
A böngésző közvetlenül nem érti --- a build eszköz fordítja sima JavaScript-té.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item JavaScript kifejezéseket \texttt{\{\}} zárójelbe írjuk: változó, függvényhívás, feltétel.
|
||||
\item Minden JSX elemnek pontosan egy gyökéreleme lehet (vagy \texttt{<>\ldots</>} fragment).
|
||||
\item A \texttt{class} HTML attribútum neve JSX-ben \texttt{className} --- a \texttt{class} JS-ben foglalt szó.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
Binary file not shown.
@@ -0,0 +1,31 @@
|
||||
\documentclass[usenames,dvipsnames,aspectratio=169,compress]{beamer}
|
||||
\usepackage{../common/webfejl}
|
||||
|
||||
\title[Webtechnológia és webalkalmazás-fejlesztés - Frontend (React)]{Webtechnológia és webalkalmazás-fejlesztés - Frontend (React)}
|
||||
\subtitle{Frontend fejlesztés React könyvtárral}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\begin{frame}[plain]
|
||||
\titlepage
|
||||
\logoalul
|
||||
\end{frame}
|
||||
|
||||
\input{react.tex}
|
||||
\input{components.tex}
|
||||
\input{hooks.tex}
|
||||
\input{state.tex}
|
||||
\input{forms.tex}
|
||||
\input{effects.tex}
|
||||
\input{routing.tex}
|
||||
\input{context.tex}
|
||||
\input{tailwind.tex}
|
||||
\input{axios.tex}
|
||||
\input{performance.tex}
|
||||
\input{testing.tex}
|
||||
\input{typescript_nextjs.tex}
|
||||
\input{build_deploy.tex}
|
||||
\input{other_relevant_libraries.tex}
|
||||
|
||||
|
||||
\end{document}
|
||||
@@ -0,0 +1,98 @@
|
||||
\section{Navigáció}
|
||||
|
||||
\begin{frame}{Mit jelent a kliensoldali navigáció?}
|
||||
\begin{block}{Hagyományos vs.\ SPA navigáció}
|
||||
Hagyományos weboldalon minden oldalváltáskor a böngésző \textbf{új HTTP kérést} küld, és teljesen újratölti az oldalt.
|
||||
SPA (Single Page Application) esetén az oldal egyszer töltődik be, a navigáció pedig JavaScript-tel történik,
|
||||
ezért gyorsabb és folyamatosabb élményt ad.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
A React Router a legelterjedtebb könyvtár erre a feladatra React alkalmazásokban.
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{React Router --- hogyan működik?}
|
||||
\begin{itemize}
|
||||
\item A \texttt{BrowserRouter} figyeli a böngésző URL-jét.
|
||||
\item A \texttt{Routes} és \texttt{Route} elemek URL mintákhoz komponenseket rendelnek.
|
||||
\item A \texttt{Link} URL-t vált teljes oldalfrissítés nélkül.
|
||||
\item A React újrarendereli a megfelelő oldalkomponenst az aktuális útvonal alapján.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}[fragile]{React Router példa kód 1/2}
|
||||
\begin{verbatim}
|
||||
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<nav>
|
||||
<Link to="/">Fooldal</Link>
|
||||
<Link to="/termekek">Termekek</Link>
|
||||
</nav>
|
||||
\end{verbatim}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}[fragile]{React Router példa kód 2/2}
|
||||
\begin{verbatim}
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/termekek" element={<Products />} />
|
||||
<Route path="/termekek/:id" element={<ProductDetails />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
||||
\end{verbatim}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Dinamikus útvonalak (React Router)}
|
||||
\begin{itemize}
|
||||
\item Paraméteres route példa: \texttt{/termekek/:id}
|
||||
\item Ha az URL \texttt{/termekek/42}, akkor a \texttt{useParams()} eredménye: \texttt{\{ id: "42" \}}
|
||||
\item Tipikusan ilyen paraméterrel kérünk le részletes adatot API-ból.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Mappa routing (file-system routing) --- mi ez?}
|
||||
\begin{block}{Alapelv}
|
||||
Mappaalapú routingnál az útvonalakat nem külön \texttt{Routes} konfigurációban írjuk,
|
||||
hanem a mappastruktúra \textbf{automatikusan} meghatározza őket.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item Ez főleg Next.js-ben elterjedt (App Router).
|
||||
\item Az \texttt{app/} mappában minden \texttt{page.tsx} egy útvonalat jelent.
|
||||
\item Dinamikus route mappanévben: \texttt{[id]}.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}[fragile]{Mappa routing példa (Next.js App Router)}
|
||||
\begin{verbatim}
|
||||
app/
|
||||
page.tsx -> /
|
||||
kapcsolat/
|
||||
page.tsx -> /kapcsolat
|
||||
termekek/
|
||||
page.tsx -> /termekek
|
||||
[id]/
|
||||
page.tsx -> /termekek/:id
|
||||
\end{verbatim}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}[fragile]{Dinamikus mappa route komponens példa}
|
||||
\begin{verbatim}
|
||||
// app/termekek/[id]/page.tsx
|
||||
export default function ProductPage({ params }) {
|
||||
return <h2>Termek azonosito: {params.id}</h2>;
|
||||
}
|
||||
\end{verbatim}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{React Router vs. mappa routing}
|
||||
\begin{itemize}
|
||||
\item \textbf{React Router:} explicit útvonal definíció a kódban (rugalmas, kontrollált).
|
||||
\item \textbf{Mappa routing:} mappaszerkezetből automatikus route (gyors indulás, kevesebb konfiguráció).
|
||||
\item Kezdőknek mindkettőt érdemes ismerni: React Router SPA-hoz, mappa routing Next.js projektekhez.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
@@ -0,0 +1,50 @@
|
||||
\section{Állapotkezelés}
|
||||
|
||||
\begin{frame}{Mi az állapot (state)?}
|
||||
\begin{block}{Analógia: a komponens "emlékezete"}
|
||||
Az állapot az, amit a komponens \textbf{megjegyez} renderelések között. Gondoljunk rá úgy, mint egy cetlire, amire a komponens feljegyzi az aktuális értékeit --- hány termék van a kosárban, be van-e jelentkezve a felhasználó, milyen szöveg van az input mezőben.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item Az állapot megváltozásakor a React \textbf{automatikusan újrarendereli} az érintett komponenst.
|
||||
\item Az állapot a komponensen \emph{belül} él --- más komponens nem látja közvetlenül.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Állapot típusok a gyakorlatban}
|
||||
\begin{itemize}
|
||||
\item \textbf{Lokális UI állapot:} csak egy komponenst érint --- pl. le van-e hajtva egy dropdown, aktív-e egy fül.
|
||||
\item \textbf{Megosztott állapot:} több komponens is olvas vagy ír belőle --- pl. a bejelentkezett felhasználó neve.
|
||||
\item \textbf{Szerverállapot:} API-ból érkező, kiszolgálón élő adat, amelyet le kell kérni és szinkronban kell tartani.
|
||||
\item \textbf{URL állapot:} az aktuális útvonal, query paraméterek --- természetesen megosztható és könyvjelzőzhető.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Egyirányú adatfolyam}
|
||||
\begin{block}{Mi ez pontosan?}
|
||||
Reactben az adatok mindig \textbf{szülőtől gyermek felé} áramlanak (props-on keresztül). A gyermek \emph{nem módosíthatja} a szülő állapotát közvetlenül --- csak egy callback függvényen (eseménykezelőn) keresztül jelezhet vissza.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item Ezért kiszámítható: mindig tudjuk, honnan ered egy érték.
|
||||
\item Hibakeresés könnyebb --- az adatfolyamot felfelé haladva követhetjük.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{State emelés (Lifting State Up)}
|
||||
\begin{itemize}
|
||||
\item Ha két testvérkomponensnek ugyanazt az adatot kell látnia, az állapotot a legközelebbi közös ősbe \textbf{emeljük fel}.
|
||||
\item Az ős kezeli az állapotot, és props-on keresztül osztja szét a gyermekek között.
|
||||
\item \textbf{Példa:} egy szűrő mező és egy lista --- mindkettőnek ugyanaz a szűrési feltétel kell, ezért azt a szülőben tároljuk.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Mikor kell külső állapotkezelő?}
|
||||
\begin{itemize}
|
||||
\item Ha az állapot emelése sok szinten keresztül megy, és a köztes komponensek csak "átpasszolják" --- ezt hívjuk \textbf{prop drilling}-nek.
|
||||
\item Ha az állapot nagyon sok helyen kell, és bonyolult szinkronizálás szükséges.
|
||||
\item Külső megoldások: \textbf{Redux Toolkit} (nagy, komplex alkalmazásokhoz), \textbf{Zustand} (könnyű, egyszerű API), \textbf{Jotai} (atomi, finomhangolt).
|
||||
\item Legtöbb esetben a beépített eszközök (useState + Context) elegendők --- ne bonyolítsuk túl.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
\section{Stílusozás}
|
||||
|
||||
\begin{frame}{A CSS megközelítések áttekintése}
|
||||
\begin{itemize}
|
||||
\item \textbf{Globális CSS:} hagyományos, minden komponens látja --- névütközések kockázatával.
|
||||
\item \textbf{CSS Modules:} minden komponensnek saját, automatikusan lokalizált CSS osztályai vannak --- nincs névütközés.
|
||||
\item \textbf{CSS-in-JS} (pl. styled-components, Emotion): közvetlenül JavaScript-ben írunk stílusokat, dinamikus értékek könnyen használhatók.
|
||||
\item \textbf{Utility-first} (Tailwind CSS): előre definiált kis osztályokat kombinálunk --- nincs saját CSS fájl.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Mi az a Tailwind CSS?}
|
||||
\begin{block}{Az alapötlet}
|
||||
A Tailwind CSS nem komponenseket, hanem apró, egy-egy CSS tulajdonságot képviselő \textbf{utility osztályokat} ad. Ezeket közvetlenül a JSX-be írjuk --- pl. \texttt{flex}, \texttt{pt-4}, \texttt{text-gray-700}.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item Előny: nem kell kitalálni osztályneveket, nincsenek névütközések, konzisztens design tokenek.
|
||||
\item Hátrány: a JSX-ben hosszú osztálylisták keletkezhetnek --- komponens-szintű absztrakciókkal kezelhető.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Design rendszer gondolkodás}
|
||||
\begin{itemize}
|
||||
\item Jól felépített alkalmazásban definiálunk \textbf{UI primitíveket}: \texttt{Button}, \texttt{Input}, \texttt{Card}, \texttt{Badge} stb.
|
||||
\item Ezek belül rejtenek el minden stílust --- a felhasználójuk csak a variánst adja meg (pl. \texttt{variant="primary"}).
|
||||
\item \textbf{Egységes spacing, színek, tipográfia:} ezeket design tokenek (Tailwind config vagy CSS változók) rögzítik, nem ismétlünk hardcoded értékeket.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Hozzáférhetőség (accessibility)}
|
||||
\begin{itemize}
|
||||
\item \textbf{Kontraszt:} a szöveg és háttér közötti kontraszt arány elégítse ki a WCAG irányelveket.
|
||||
\item \textbf{Fókuszállapot:} billentyűzettel is navigálható legyen az oldal --- a fókuszjelzőt ne távolítsuk el.
|
||||
\item \textbf{Szemantikus HTML:} helyes heading hierarchia, gomb valóban \texttt{<button>}, ne \texttt{<div onClick>}.
|
||||
\item \textbf{ARIA attribútumok:} ahol a HTML szemantika nem elég (pl. egyedi komponensek).
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
@@ -0,0 +1,33 @@
|
||||
\section{Tesztelés}
|
||||
|
||||
\begin{frame}{Miért teszteljünk?}
|
||||
\begin{block}{Az alapmotiváció}
|
||||
A tesztek nem csak hibákat fednek fel --- \textbf{dokumentálják a szándékolt viselkedést} és biztosítékot adnak arra, hogy jövőbeli módosítások nem törnek el meglévő funkciókat. Refaktorálás és csapatmunka esetén különösen értékes.
|
||||
\end{block}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Tesztelési szintek}
|
||||
\begin{itemize}
|
||||
\item \textbf{Unit teszt:} egyetlen függvény, hook vagy logikai egység viselkedését ellenőrzi, függetlenül a többitől. Gyors, izolált.
|
||||
\item \textbf{Integrációs teszt:} több komponens vagy réteg együttműködését vizsgálja --- pl. egy form elküldésének teljes folyamata, beleértve az állapotkezelést.
|
||||
\item \textbf{E2E teszt} (End-to-End): egy valódi böngészőben szimulál felhasználói lépéseket --- pl. Playwright-tal. Lassabb, de a legvalóságosabb visszajelzést adja.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Ajánlott eszközök}
|
||||
\begin{itemize}
|
||||
\item \textbf{Vitest:} modern, Vite-alapú tesztfuttató --- gyors, könnyen konfigurálható, ES module-barát.
|
||||
\item \textbf{Jest:} régebben az iparági standard, nagyon elterjedt, rengeteg dokumentáció.
|
||||
\item \textbf{React Testing Library:} komponenseket \emph{felhasználói szemszögből} tesztel --- nem implementációs részleteket, hanem azt, amit a felhasználó lát és tehet.
|
||||
\item \textbf{Mock Service Worker (MSW):} API válaszokat szimulál hálózati szinten --- nem kell valódi szerver a tesztekhez.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Mit érdemes tesztelni?}
|
||||
\begin{itemize}
|
||||
\item \textbf{Kritikus folyamatok:} regisztráció, bejelentkezés, fizetés, jogosultság-ellenőrzés.
|
||||
\item \textbf{Hibaállapotok:} mi történik, ha a hálózat megszakad, a szerver hibát ad, az input érvénytelen?
|
||||
\item \textbf{Szélsőértékek (edge case):} üres lista, nagyon hosszú szöveg, speciális karakterek.
|
||||
\item \textbf{Hozzáférhetőség:} a kritikus UI elemek megfelelő ARIA szerepkörrel és felirattal rendelkeznek-e?
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
@@ -0,0 +1,35 @@
|
||||
\section{TypeScript / Next.js}
|
||||
|
||||
\begin{frame}{Mi az a TypeScript?}
|
||||
\begin{block}{JavaScript + típusok}
|
||||
A TypeScript a JavaScript egy \textbf{típusos kibővítése}: szintaktikailag ugyanolyan, de lehetővé teszi, hogy megmondjuk, egy változó szám-e, szöveg-e, vagy éppen egy konkrét adatstruktúra. A böngésző ezután sem érti --- fordításkor sima JavaScript-té alakul.
|
||||
\end{block}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Miért TypeScript Reacthez?}
|
||||
\begin{itemize}
|
||||
\item \textbf{Korai hibajelzés:} a szerkesztő azonnal jelzi, ha rossz típusú props-ot adunk át egy komponensnek --- nem kell a böngészőben futtatni.
|
||||
\item \textbf{Öndokumentáló kód:} a props típusai rögtön megmondják, mit vár a komponens --- nincs szükség külön kommentre.
|
||||
\item \textbf{Karbantarthatóság:} refaktoráláskor a fordító jelzi, hol kell módosítani --- nagyobb változtatások biztonságosabbak.
|
||||
\item Kis projekten is megéri a tanulási görbéje, mert a hosszabb távú haszon jelentős.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Mi az a Next.js?}
|
||||
\begin{block}{React + szerver}
|
||||
A Next.js egy teljes React keretrendszer: beépített routing, szerveroldali renderelés (SSR), statikus oldalak generálása (SSG), képoptimalizálás, és más funkciók --- mindez konfiguráció nélkül.
|
||||
\end{block}
|
||||
\vspace{0.5em}
|
||||
\begin{itemize}
|
||||
\item \textbf{SSR (Server-Side Rendering):} a szerver minden kérésnél rendereli az oldalt --- friss adatok, jó SEO.
|
||||
\item \textbf{SSG (Static Site Generation):} build-időben generál HTML-t --- villámgyors, CDN-ről tálalható.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Mikor melyiket válasszuk?}
|
||||
\begin{itemize}
|
||||
\item \textbf{Vite + React (SPA):} admin felületek, dashboardok, belső eszközök --- ahol a SEO nem kritikus, a bejelentkezés után töltődik be a tartalom.
|
||||
\item \textbf{Next.js:} publikus weboldalak, e-commerce, blog, dokumentáció --- ahol a keres�'optimalizálás és a gyors els�' betöltés fontos.
|
||||
\item \textbf{Mindkét esetben ajánlott:} TypeScript, lint, automatikus tesztek, CI/CD csővezeték.
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
Reference in New Issue
Block a user