React

ref, DOM e stato: chi possiede cosa

useRef conserva un valore senza ri-renderizzare, lo stato ri-renderizza il componente: la scelta dipende da chi deve vedere il cambiamento.

In sintesi

  • Se il valore compare nel markup è stato, se lo leggi solo in un effetto o in un gestore è una ref.
  • Cambiare una ref non ridisegna il componente e non avvisa nessuno: nessun effetto parte.
  • Una ref letta o scritta durante il render rompe il modello, perché React può scartare quel render.

Lo stato possiede ciò che disegna il render, la ref possiede ciò che serve al comportamento: un nodo del DOM, un timer, l'ultimo valore visto. Cambiare una ref non ridisegna nulla.

La regola in una riga

Se il valore compare nel markup, è stato. Se lo leggi solo dentro un effetto o un gestore di eventi, è una ref. Nel dubbio chiediti chi deve accorgersi del cambiamento: se la risposta è l'utente, serve stato.

Il caso eseguibile

import { useEffect, useRef, useState } from "react";

export function CampoRicerca() {
  const input = useRef(null);
  const tentativi = useRef(0);
  const [testo, setTesto] = useState("");

  useEffect(() => {
    input.current?.focus();
  }, []);

  function invia(e) {
    e.preventDefault();
    tentativi.current += 1;
  }

  return (
    
       setTesto(e.target.value)}
      />
      Cerca
    
  );
}

Il campo è controllato dallo stato, il nodo e il contatore vivono nelle ref. Il contatore non compare a schermo: se dovesse comparire, diventerebbe stato e il componente si ridisegnerebbe a ogni invio.

Ref e server component

Le ref richiedono un client component: puntano a un nodo del browser, che sul server non esiste. Un componente con useRef e senza direttiva di client viene rifiutato in build, non a runtime.

Misurare invece di indovinare

Per leggere larghezza o posizione usa una callback ref con ResizeObserver, non una ref letta durante il render. Il valore misurato è un dato del browser, quindi appartiene a un effetto, non al corpo del componente.

La categoria input raccoglie i campi del catalogo, con un input di chat che gestisce focus e altezza; un esempio di blocco è input-10.

La limitazione

Una ref non notifica nessuno: due componenti non possono sincronizzarsi su di essa senza uno stato che li svegli. Inoltre la mutazione durante il render è invisibile a React, che in concurrent rendering può scartare il calcolo e lasciare la scrittura al suo posto.

Dove continuare

Il confine fra client e server è in un hook importato in un server component; il doppio avvio degli effect è in useEffect due volte in sviluppo; come si legge la documentazione è in leggere la documentazione React. Il confronto con Vue è in Vue 3 vs React.

Domande frequenti

Perché cambiare una ref non aggiorna la pagina?

Perché React non osserva le ref. Solo lo stato e le props avviano un render, quindi un valore in ref cambia senza che l'interfaccia lo sappia.

Posso usare una ref al posto dello stato per un contatore?

Sì se il contatore non compare mai a schermo e serve solo alla logica. Appena deve essere visibile o cambiare il markup, serve stato.

A cosa serve ref su un elemento DOM?

A chiamare metodi che React non espone, come focus, select o scrollIntoView. Per leggere valori di un campo controllato basta lo stato.

Una ref sopravvive ai ri-render?

Sì, l'oggetto è lo stesso per tutta la vita del componente. Cambia solo quando il componente viene smontato e ricreato, per esempio con una key diversa.

Perché la ref è null al primo render?

Perché React la riempie dopo aver creato il nodo. Va letta in un effetto o in un gestore, non nel corpo del componente.