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
statelubprops - 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ładnia | Kiedy 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
- React renderuje komponent
- DOM jest aktualizowany
- React uruchamia
useEffect - 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>
);
}
tuff quest