Tutorial

React Hooks kezdőknek: Teljes útmutató

Kristóf Kristóf
2025. január 15.
10 perc olvasás

A React Hooks forradalmasították a React komponensek írását. Ebben az átfogó útmutatóban megtanulod, hogyan használd a Hooks-okat nulláról, gyakorlati példákkal és best practice-ekkel.

Mi az a Hook?

A Hooks olyan függvények, amelyek lehetővé teszik, hogy "beakasztsd magad" a React funkcióiba funkcionális komponensekből. Korábban csak class komponensekben lehetett state-t és lifecycle metódusokat használni - most már funkcionális komponensekben is!

Miért használjunk Hooks-okat?

  • 🎯 Egyszerűbb kód: Kevesebb boilerplate, olvashatóbb logika
  • ♻️ Kód újrafelhasználás: Custom Hooks-okkal könnyen megoszthatjuk a logikát
  • 🧩 Jobb szervezés: Kapcsolódó logika egy helyen marad
  • Könnyebb tesztelés: Funkcionális komponensek egyszerűbben tesztelhetők

1. useState - Állapotkezelés

A useState a legalapvetőbb Hook. Lehetővé teszi, hogy state-t adj hozzá funkcionális komponensedhez:

Egyszerű példa:

import { useState } from 'react';

function Counter() {
  // [state változó, frissítő függvény] = useState(kezdőérték)
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Számláló: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Növel
      </button>
      <button onClick={() => setCount(count - 1)}>
        Csökkent
      </button>
      <button onClick={() => setCount(0)}>
        Reset
      </button>
    </div>
  );
}

Összetett state:

function UserProfile() {
  const [user, setUser] = useState({
    name: '',
    email: '',
    age: 0
  });

  const updateName = (newName) => {
    setUser({
      ...user,        // Spread operátor - megtartjuk a többi értéket
      name: newName   // Csak a name-et frissítjük
    });
  };

  return (
    <input 
      value={user.name}
      onChange={(e) => updateName(e.target.value)}
    />
  );
}

Funkcionális frissítés:

function Counter() {
  const [count, setCount] = useState(0);

  const incrementTwice = () => {
    // ❌ Ez NEM fog 2-vel növelni
    setCount(count + 1);
    setCount(count + 1);

    // ✅ Ez IGEN
    setCount(prev => prev + 1);
    setCount(prev => prev + 1);
  };

  return <button onClick={incrementTwice}>+2</button>;
}

2. useEffect - Mellékhatások kezelése

A useEffect lehetővé teszi mellékhatások (side effects) végrehajtását komponenseidben. Példák: adatbetöltés, DOM manipuláció, feliratkozások.

Alapvető használat:

import { useState, useEffect } from 'react';

function UserList() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // Ez a kód minden render után lefut
    fetch('/api/users')
      .then(res => res.json())
      .then(data => {
        setUsers(data);
        setLoading(false);
      });
  }, []); // Üres dependency array = csak mountoláskor fut

  if (loading) return <p>Töltés...</p>;

  return (
    <ul>
      {users.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}

Dependency array:

function SearchResults({ query }) {
  const [results, setResults] = useState([]);

  useEffect(() => {
    // Csak akkor fut, ha a query megváltozik
    fetch(`/api/search?q=${query}`)
      .then(res => res.json())
      .then(setResults);
  }, [query]); // query a dependency

  return <ResultsList results={results} />;
}

Cleanup funkció:

function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds(s => s + 1);
    }, 1000);

    // Cleanup: komponens unmountkor fut
    return () => clearInterval(interval);
  }, []);

  return <div>Eltelt idő: {seconds} másodperc</div>;
}

3. useContext - Kontextus használata

A useContext lehetővé teszi, hogy komponensek között prop drilling nélkül oszd meg az adatokat:

import { createContext, useContext, useState } from 'react';

// Kontextus létrehozása
const ThemeContext = createContext();

function App() {
  const [theme, setTheme] = useState('light');

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  return <ThemeButton />;
}

function ThemeButton() {
  // Kontextus használata
  const { theme, setTheme } = useContext(ThemeContext);

  return (
    <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
      Jelenlegi téma: {theme}
    </button>
  );
}

4. useReducer - Komplex state kezelés

A useReducer a useState alternatívája összetett state logikához:

import { useReducer } from 'react';

// Reducer függvény
function cartReducer(state, action) {
  switch (action.type) {
    case 'ADD_ITEM':
      return {
        ...state,
        items: [...state.items, action.payload]
      };
    case 'REMOVE_ITEM':
      return {
        ...state,
        items: state.items.filter(item => item.id !== action.payload)
      };
    case 'CLEAR_CART':
      return { ...state, items: [] };
    default:
      return state;
  }
}

function ShoppingCart() {
  const [cart, dispatch] = useReducer(cartReducer, { items: [] });

  const addItem = (item) => {
    dispatch({ type: 'ADD_ITEM', payload: item });
  };

  return (
    <div>
      <button onClick={() => addItem({ id: 1, name: 'Termék' })}>
        Hozzáad
      </button>
      <button onClick={() => dispatch({ type: 'CLEAR_CART' })}>
        Kosár ürítése
      </button>
    </div>
  );
}

5. useRef - Referenciák kezelése

A useRef lehetővé teszi DOM elemek elérését és megváltozhatatlan értékek tárolását:

import { useRef, useEffect } from 'react';

function FocusInput() {
  const inputRef = useRef(null);

  useEffect(() => {
    // Automatikus focus mountoláskor
    inputRef.current.focus();
  }, []);

  return <input ref={inputRef} type="text" />;
}

// Renderelés számának követése
function RenderCounter() {
  const renderCount = useRef(0);

  useEffect(() => {
    renderCount.current += 1;
  });

  return <p>Renderelések száma: {renderCount.current}</p>;
}

6. useMemo és useCallback - Optimalizálás

Ezek a Hooks segítenek a teljesítmény optimalizálásában:

useMemo - Értékek memoizálása:

import { useMemo } from 'react';

function ExpensiveComponent({ data }) {
  // Ez a számítás csak akkor fut újra, ha data változik
  const sortedData = useMemo(() => {
    console.log('Expensive sorting...');
    return data.sort((a, b) => a.value - b.value);
  }, [data]);

  return <DataList data={sortedData} />;
}

useCallback - Függvények memoizálása:

import { useCallback } from 'react';

function ParentComponent() {
  const [count, setCount] = useState(0);

  // Ez a függvény csak egyszer jön létre
  const handleClick = useCallback(() => {
    console.log('Button clicked');
  }, []);

  return (
    <div>
      <ChildComponent onClick={handleClick} />
      <button onClick={() => setCount(count + 1)}>
        Count: {count}
      </button>
    </div>
  );
}

Custom Hooks - Saját Hooks készítése

A legjobb dolog a Hooks-okban: létrehozhatod a sajátokat!

// useLocalStorage custom hook
function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    const item = localStorage.getItem(key);
    return item ? JSON.parse(item) : initialValue;
  });

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
}

// Használat
function App() {
  const [name, setName] = useLocalStorage('username', '');

  return (
    <input 
      value={name}
      onChange={(e) => setName(e.target.value)}
    />
  );
}

Még egy példa - useFetch:

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(data => {
        setData(data);
        setLoading(false);
      })
      .catch(err => {
        setError(err);
        setLoading(false);
      });
  }, [url]);

  return { data, loading, error };
}

// Használat
function UserProfile({ userId }) {
  const { data, loading, error } = useFetch(`/api/users/${userId}`);

  if (loading) return <p>Töltés...</p>;
  if (error) return <p>Hiba: {error.message}</p>;

  return <div>{data.name}</div>;
}

Hooks szabályok

A Hooks használatához be kell tartani két fontos szabályt:

  • Csak a legfelső szinten hívd őket - nem ciklusokban, feltételekben vagy nested függvényekben
  • Csak React függvényekből hívd őket - funkcionális komponensekből vagy custom Hooks-okból
// ❌ ROSSZ
function Component() {
  if (condition) {
    useState(0); // NE!
  }
}

// ✅ JÓ
function Component() {
  const [value, setValue] = useState(0);
  
  if (condition) {
    setValue(10); // OK!
  }
}

Best Practices

  • Használj ESLint plugin-t: eslint-plugin-react-hooks
  • Ne felejtsd el a dependency array-t a useEffect-ben
  • Custom Hooks-okat mindig use prefixszel nevezz el
  • Ne túlozd el a memoizálást - csak ha valóban szükséges
  • Tartsd egyszerűnek a komponenseket - ha túl komplex, bontsd kisebbekre

Összegzés

A React Hooks modern, hatékony módot kínálnak a React komponensek írására. A useState és useEffect az alapok, de a többi Hook és a custom Hooks valódi szupererőket adnak.

A legjobb módszer a tanulásra: gyakorlás! Kezdj el Hooks-okat használni a projektjeidben, kísérletezz, és hamarosan természetessé válik. Hajrá!