forwardRef

Nota bene

Questa pagina è stata tradotta automaticamente e supervisionata da un maintainer. Un’ulteriore revisione da parte della community sarebbe comunque utile. Migliora questa traduzione.

Deprecato

In React 19, forwardRef non è più necessario. Passa ref come prop.

forwardRef sarà deprecato in una futura release. Scopri di più qui.

forwardRef ti permette di esporre un nodo DOM al componente genitore con un ref.

const SomeComponent = forwardRef(render)

Reference

forwardRef(render)

Chiama forwardRef() per far sì che il tuo componente riceva un ref e lo inoltri a un componente figlio:

import { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
// ...
});

Vedi altri esempi sotto.

Parameters

  • render: La funzione render del tuo componente. React chiama questa funzione con le props e il ref che il tuo componente ha ricevuto dal genitore. Il JSX che restituisci sarà l’output del tuo componente.

Returns

forwardRef restituisce un componente React che puoi renderizzare in JSX. A differenza dei componenti React definiti come funzioni semplici, un componente restituito da forwardRef può anche ricevere una prop ref.

Caveats

  • In Strict Mode, React chiamerà la tua funzione render due volte per aiutarti a trovare impurità accidentali. Questo comportamento vale solo in sviluppo e non influisce sulla produzione. Se la tua funzione render è pura (come dovrebbe essere), non dovrebbe influire sulla logica del tuo componente. Il risultato di una delle chiamate verrà ignorato.

Funzione render

forwardRef accetta una funzione render come argomento. React chiama questa funzione con props e ref:

const MyInput = forwardRef(function MyInput(props, ref) {
return (
<label>
{props.label}
<input ref={ref} />
</label>
);
});

Parameters

  • props: Le props passate dal componente genitore.

  • ref: L’attributo ref passato dal componente genitore. Il ref può essere un oggetto o una funzione. Se il componente genitore non ha passato un ref, sarà null. Dovresti inoltrare il ref che ricevi a un altro componente oppure passarlo a useImperativeHandle.

Returns

forwardRef restituisce un componente React che puoi renderizzare in JSX. A differenza dei componenti React definiti come funzioni semplici, il componente restituito da forwardRef può ricevere una prop ref.


Usage

Esporre un nodo DOM al componente genitore

Per impostazione predefinita, i nodi DOM di ogni componente sono privati. A volte però è utile esporre un nodo DOM al genitore — ad esempio, per metterlo a fuoco. Per attivare questa opzione, avvolgi la definizione del componente in forwardRef():

import { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
const { label, ...otherProps } = props;
return (
<label>
{label}
<input {...otherProps} />
</label>
);
});

Riceverai un ref come secondo argomento dopo le props. Passalo al nodo DOM che vuoi esporre:

import { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
const { label, ...otherProps } = props;
return (
<label>
{label}
<input {...otherProps} ref={ref} />
</label>
);
});

Questo permette al componente genitore Form di accedere al nodo DOM <input> esposto da MyInput:

function Form() {
const ref = useRef(null);

function handleClick() {
ref.current.focus();
}

return (
<form>
<MyInput label="Enter your name:" ref={ref} />
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}

Questo componente Form passa un ref a MyInput. Il componente MyInput inoltra quel ref al tag browser <input>. Di conseguenza, il componente Form può accedere a quel nodo DOM <input> e chiamare focus() su di esso.

Tieni presente che esporre un ref al nodo DOM interno al tuo componente complica il cambiamento dei dettagli interni in seguito. In genere esporrai nodi DOM da componenti riutilizzabili di basso livello come pulsanti o campi di testo, ma non lo farai per componenti a livello applicativo come un avatar o un commento.

Esempi di inoltro di un ref

Esempio 1 di 2:
Mettere a fuoco un campo di testo

Cliccando il pulsante metterai a fuoco l’input. Il componente Form definisce un ref e lo passa al componente MyInput. Il componente MyInput inoltra quel ref al <input> del browser. Questo permette al componente Form di mettere a fuoco l’<input>.

import { useRef } from 'react';
import MyInput from './MyInput.js';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
  }

  return (
    <form>
      <MyInput label="Enter your name:" ref={ref} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}


Inoltrare un ref attraverso più componenti

Invece di inoltrare un ref a un nodo DOM, puoi inoltrarlo al tuo componente, come MyInput:

const FormField = forwardRef(function FormField(props, ref) {
// ...
return (
<>
<MyInput ref={ref} />
...
</>
);
});

Se quel componente MyInput inoltra un ref al suo <input>, un ref a FormField ti darà accesso a quell’<input>:

function Form() {
const ref = useRef(null);

function handleClick() {
ref.current.focus();
}

return (
<form>
<FormField label="Enter your name:" ref={ref} isRequired={true} />
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}

Il componente Form definisce un ref e lo passa a FormField. Il componente FormField inoltra quel ref a MyInput, che lo inoltra a un nodo DOM <input> del browser. È così che Form accede a quel nodo DOM.

import { useRef } from 'react';
import FormField from './FormField.js';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
  }

  return (
    <form>
      <FormField label="Enter your name:" ref={ref} isRequired={true} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}


Esporre un handle imperativo invece di un nodo DOM

Invece di esporre un intero nodo DOM, puoi esporre un oggetto personalizzato, chiamato handle imperativo, con un insieme più ristretto di metodi. Per farlo, devi definire un ref separato per contenere il nodo DOM:

const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);

// ...

return <input {...props} ref={inputRef} />;
});

Passa il ref che hai ricevuto a useImperativeHandle e specifica il valore che vuoi esporre al ref:

import { forwardRef, useRef, useImperativeHandle } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);

useImperativeHandle(ref, () => {
return {
focus() {
inputRef.current.focus();
},
scrollIntoView() {
inputRef.current.scrollIntoView();
},
};
}, []);

return <input {...props} ref={inputRef} />;
});

Se un componente ottiene un ref a MyInput, riceverà solo il tuo oggetto { focus, scrollIntoView } invece del nodo DOM. Questo ti permette di limitare al minimo le informazioni che esponi sul tuo nodo DOM.

import { useRef } from 'react';
import MyInput from './MyInput.js';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
    // Non funzionerà perché il nodo DOM non è esposto:
    // ref.current.style.opacity = 0.5;
  }

  return (
    <form>
      <MyInput placeholder="Enter your name" ref={ref} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}

Leggi di più sull’uso degli handle imperativi.

Insidia

Non abusare dei ref. Dovresti usare i ref solo per comportamenti imperativi che non puoi esprimere come props: ad esempio, scorrere fino a un nodo, mettere a fuoco un nodo, avviare un’animazione, selezionare del testo e così via.

Se puoi esprimere qualcosa come prop, non dovresti usare un ref. Ad esempio, invece di esporre un handle imperativo come { open, close } da un componente Modal, è meglio accettare isOpen come prop, come <Modal isOpen={isOpen} />. Gli Effetti possono aiutarti a esporre comportamenti imperativi tramite props.


Troubleshooting

Il mio componente è avvolto in forwardRef, ma il ref verso di esso è sempre null

Di solito significa che hai dimenticato di usare effettivamente il ref che hai ricevuto.

Ad esempio, questo componente non fa nulla con il suo ref:

const MyInput = forwardRef(function MyInput({ label }, ref) {
return (
<label>
{label}
<input />
</label>
);
});

Per risolvere, passa il ref a un nodo DOM o a un altro componente che può accettare un ref:

const MyInput = forwardRef(function MyInput({ label }, ref) {
return (
<label>
{label}
<input ref={ref} />
</label>
);
});

Il ref a MyInput potrebbe anche essere null se parte della logica è condizionale:

const MyInput = forwardRef(function MyInput({ label, showInput }, ref) {
return (
<label>
{label}
{showInput && <input ref={ref} />}
</label>
);
});

Se showInput è false, il ref non verrà inoltrato a nessun nodo e un ref a MyInput resterà vuoto. È particolarmente facile non accorgersene se la condizione è nascosta dentro un altro componente, come Panel in questo esempio:

const MyInput = forwardRef(function MyInput({ label, showInput }, ref) {
return (
<label>
{label}
<Panel isExpanded={showInput}>
<input ref={ref} />
</Panel>
</label>
);
});