PLANTA 5 · Sessió 5 · Estat, esdeveniments i formularis
El cor de l'estat
Sistema a restaurar: Caixes i carro de la compra
- Alerta
- Manual
- Reptes
- Mòdul
Aquesta planta ja té llum. Pots tornar-la a jugar per repassar, però la puntuació desada no canviarà.
Manual de la planta
0 / 5Desbloqueja les 5 pàgines del manual per obrir els reptes. Llegeix-les bé: els reptes en pregunten els detalls.
Per què una variable normal no serveix
Si canvies una variable normal, React no se n'assabenta i no torna a dibuixar el component. useState retorna el valor i una funció per canviar-lo; cada crida a aquesta funció fa que React torni a dibuixar el component amb el valor nou.
const [punts, setPunts] = useState(0);
<button onClick={() => setPunts(punts + 1)}>Suma</button>
<p>Tens {punts} punts</p>| Fragment | Què fa |
|---|---|
useState(0) | Crea un estat que comença valent 0. |
const [punts, setPunts] | Desestructura l'array: el valor actual i la funció per canviar-lo. |
setPunts(punts + 1) | Demana el valor nou. React torna a dibuixar el component i punts ja val 1. |
Les tres regles de useState
- Els ganxos, a dalt de tot. Mai dins d'un
if, d'un bucle o d'una funció interna: React identifica cadauseStateper l'ordre. - No mutis l'estat.
llista.push(x)modifica el mateix array: React veu el mateix objecte i no repinta. Crea'n un de nou:[...llista, x],.filter(),.map(),{ ...objecte, camp: valor }. - El canvi no és immediat. El valor nou arriba al dibuixat següent. Si encadenes canvis que depenen de l'anterior, fes servir la forma funcional.
// Suma 1, no 3: punts val 0 a les tres línies
setPunts(punts + 1);
setPunts(punts + 1);
setPunts(punts + 1);
// Suma 3: cada crida rep el valor de l'anterior
setPunts((p) => p + 1);
setPunts((p) => p + 1);
setPunts((p) => p + 1);Esdeveniments, llistes filtrades i la key
onClick={() => onAfegir(producte)}: passem una funció que cridarà l'altra en clicar.onClick={onAfegir(producte)}la crida en dibuixar.- L'objecte d'esdeveniment porta el valor del camp:
e.target.value. - La llista visible no és estat: es calcula a cada dibuixat amb
filtera partir de les dades i del text del cercador (estat derivat). El mateix amb el total del carro. - La
keyés l'id de la dada, mai l'índex: si la llista es filtra o s'ordena, l'índex canvia d'element.
const [text, setText] = useState('');
const visibles = productes.filter((p) =>
p.nom.toLowerCase().includes(text.trim().toLowerCase()),
);
<input value={text} onChange={(e) => setText(e.target.value)} />
{visibles.map((p) => (
<TargetaProducte key={p.id} producte={p} onAfegir={onAfegir} />
))}Formularis controlats
Un camp controlat té value lligat a l'estat i un onChange que l'actualitza: React és qui mana. Si poses value sense onChange, el camp no deixa escriure.
const BUIT = { nom: '', correu: '', missatge: '' };
const [dades, setDades] = useState(BUIT);
function canvia(camp: keyof Formulari, valor: string) {
setDades({ ...dades, [camp]: valor });
}
function envia(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
const trobats = validar(dades);
setErrors(trobats);
if (Object.keys(trobats).length === 0) {
setEnviat(true);
setDades(BUIT);
}
}| Fragment | Què fa |
|---|---|
{ ...dades, [camp]: valor } | Objecte nou amb tots els camps d'abans i només el que toca canviat. |
e.preventDefault(); | Sense això, el navegador envia el formulari i recarrega la pàgina. |
validar(dades) | Funció a part que retorna un objecte d'errors. Es pot provar sola. |
Object.keys(trobats).length === 0 | Si no hi ha cap error, es dona per enviat i es buida el formulari. |
Aixecar l'estat i useEffect
Si dos components necessiten la mateixa dada (la capçalera i el catàleg necessiten el carro), l'estat puja al pare comú (App). Les dades baixen com a props; les accions baixen com a funcions.
useEffect executa codi després de dibuixar. La llista de dependències diu quan: [carro] = cada cop que canvia el carro; [] = només el primer cop.
const [carro, setCarro] = useState<LiniaCarro[]>(carregaCarro);
const unitats = carro.reduce((suma, linia) => suma + linia.unitats, 0);
useEffect(() => {
localStorage.setItem(CLAU, JSON.stringify(carro));
}, [carro]);| Fragment | Què fa |
|---|---|
useState(carregaCarro) | Passem la funció (sense parèntesis): React només la crida el primer cop per llegir el carro desat. |
carro.reduce(…, 0) | Estat derivat: les unitats es calculen, no es guarden a part. |
JSON.stringify(carro) | localStorage només guarda text: convertim l'array a JSON. |
}, [carro]); | L'efecte s'executa després de cada dibuixat en què el carro ha canviat. |
Planta restaurada · Caixes i carro de la compra
El cor de PratShop torna a bategar: el carro suma, es desa i la capçalera ho sap.
- XP
- 0
- Bonus ratxa
- 0
- Errors
- 0
- Pistes
- 0
- Estrelles
- ☆☆☆
Anota la lletra i la seva posició: al terrat hauràs de compilar l'ordre de reinici.