Quest: Obiekt, map i useState

useState + useEfect

useState

  • przechowuje dane (state)
  • setState → powoduje render
  • UI automatycznie podąża za state
  • używany do:
    • danych formularzy
    • liczników
    • warunkowego renderowania
  • nie służy do efektów ubocznych

useEffect

  • wykonuje kod po renderze
  • reaguje na zmiany state lub props
  • służy do efektów ubocznych
  • nie renderuje UI

Typowe użycia:fetch, localStorage, subskrypcje, timery, event listenery

Dependency array -> useEffect(fn, deps)

SkładniaKiedy efekt się wykona
useEffect(fn)po każdym renderze
useEffect(fn, [])tylko po pierwszym renderze
useEffect(fn, [count])po pierwszym i gdy count się zmieni
  • wszystko użyte w efekcie i zmienne → powinno być w deps

Kluczowa reguła decyzyjna

  • kończy się JSX-em → bez useEffect
  • dotyka świata zewnętrznego → useEffect

Mentalny model

  1. React renderuje komponent
  2. DOM jest aktualizowany
  3. React uruchamia useEffect
  4. Effect może zmienić state → kolejny render

useState trzyma dane, a useEffect pozwala wykonać kod, gdy te dane się zmienią albo po wejściu/wyjściu komponentu.

components/Dodawanie.jsx

import { useState, useEffect } from 'react';

export function Dodawanie({ onAdd }) {
  const [nazwa, setNazwa] = useState('');
  const [plik, setPlik] = useState('');
  const [opis, setOpis] = useState('');
  const [plikValid, setPlikValid] = useState(true); // stan walidacji
  const [plikTouched, setPlikTouched] = useState(false); // czy użytkownik zaczął wpisywać

  const klik = () => {
    if (!nazwa || !plik || !opis || !plikValid) return;

    onAdd({ nazwa, plik, opis });

    setNazwa('');
    setPlik('');
    setOpis('');
    setPlikTouched(false); // resetujemy touch po dodaniu
    setPlikValid(true);    // resetujemy walidację
  };

  // useEffect do walidacji pola plik
  useEffect(() => {
    if (!plikTouched) return; // walidacja działa dopiero po pierwszym wpisaniu

    const handler = setTimeout(() => {
      setPlikValid(plik.startsWith('http'));
    }, 500); // 500ms opóźnienia

    return () => clearTimeout(handler);
  }, [plik, plikTouched]);

  return (
    <div>
      <h3>Dodaj widoczek</h3>

      <input
        placeholder="Nazwa"
        value={nazwa}
        onChange={e => setNazwa(e.target.value)}
      />

      <input
        placeholder="Link"
        value={plik}
        onChange={e => {
          setPlik(e.target.value);
          if (!plikTouched) setPlikTouched(true); // aktywujemy walidację po pierwszym wpisie
        }}
      />
      {plikTouched && !plikValid && (
        <div style={{ color: 'red' }}>Link musi zaczynać się od http</div>
      )}

      <input
        placeholder="Opis"
        value={opis}
        onChange={e => setOpis(e.target.value)}
      />

      <br />
      <button onClick={klik} disabled={!plikValid}>Dodaj</button>
    </div>
  );
}

Jedna odpowiedź

Twój komentarz

Zapisz moje dane, adres e-mail i witrynę w przeglądarce aby wypełnić dane podczas pisania kolejnych komentarzy.