useImperativeHandle

useImperativeHandle est un Hook React qui vous permet de personnaliser la référence exposée comme ref.

useImperativeHandle(ref, createHandle, dependencies?)

Référence

useImperativeHandle(ref, createHandle, dependencies?)

Appelez useImperativeHandle au niveau racine de votre composant pour personnaliser la ref qu’il expose :

import { forwardRef, useImperativeHandle } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
useImperativeHandle(ref, () => {
return {
// ... vos méthodes ...
};
}, []);
// ...

Voir d’autres exemples ci-dessous.

Paramètres

  • ref : la ref que vous avez reçue comme second argument depuis la fonction de rendu de forwardRef.

  • createHandle : une fonction ne prenant aucun argument, qui renvoie la ref que vous souhaitez effectivement exposer. Cette ref peut être de n’importe quel type. En général, vous renverrez un objet avec les méthodes que vous souhaitez exposer.

  • dependencies optionnelles : la liste des valeurs réactives référencées par le code de createHandle. Les valeurs réactives comprennent les props, les variables d’état et toutes les variables et fonctions déclarées localement dans le corps de votre composant. Si votre linter est configuré pour React, il vérifiera que chaque valeur réactive concernée est bien spécifiée comme dépendance. La liste des dépendances doit avoir un nombre constant d’éléments et utiliser un littéral défini à la volée, du genre [dep1, dep2, dep3]. React comparera chaque dépendance à sa valeur précédente au moyen de la comparaison Object.is. Si un nouveau rendu résulte d’une modification à une dépendance, ou si vous avez omis cet argument, la fonction createHandle sera réexécutée et la référence fraîchement créée sera affectée à la ref.

Valeur renvoyée

useImperativeHandle renvoie undefined.


Utilisation

Fournir une référence personnalisée au composant parent

Par défaut, les composants n’exposent pas leurs nœuds DOM aux composants parents. Par exemple, si vous souhaitez que le composant parent de MyInput ait accès au nœud DOM <input>, vous devez le permettre explicitement avec forwardRef :

import { forwardRef } from 'react';

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

Dans le code ci-avant, une ref à MyInput recevra le nœud DOM <input>. Cependant, vous pouvez plutôt exposer une valeur personnalisée. Pour définir vous-même la référence à exposer, appelez useImperativeHandle au niveau racine de votre composant :

import { forwardRef, useImperativeHandle } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
useImperativeHandle(ref, () => {
return {
// ... vos méthodes ...
};
}, []);

return <input {...props} />;
});

Remarquez que dans le code ci-avant, la ref n’est plus transmise au <input>.

Supposons par exemple que vous ne souhaitiez pas exposer l’intégralité du nœud DOM <input>, mais seulement deux de ses méthodes : focus et scrollIntoView. Pour y parvenir, conservez le véritable nœud DOM dans une ref distincte, puis utilisez useImperativeHandle pour exposer un objet avec seulement les méthodes que vous souhaitez permettre au composant parent d’appeler :

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} />;
});

Désormais, si le composant parent récupère une ref sur MyInput, il ne pourra plus appeler que ses méthodes focus et scrollIntoView. Il n’aura pas un accès complet au nœud DOM <input> sous-jacent.

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

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

  function handleClick() {
    ref.current.focus();
    // Ça ne marcherait pas, car le nœud DOM n'est pas exposé :
    // ref.current.style.opacity = 0.5;
  }

  return (
    <form>
      <MyInput placeholder="Saisissez votre nom :" ref={ref} />
      <button type="button" onClick={handleClick}>
        Modifier
      </button>
    </form>
  );
}


Exposer vos propres méthodes impératives

Les méthodes que vous exposez via un objet impératif n’ont pas l’obligation de correspondre à des méthodes du DOM. Par exemple, ce composant Post expose une méthode scrollAndFocusAddComment via un objet impératif. Elle permet au Page parent de faire défiler la liste des commentaires et d’activer le champ de saisie lorsque vous cliquez sur le bouton :

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

export default function Page() {
  const postRef = useRef(null);

  function handleClick() {
    postRef.current.scrollAndFocusAddComment();
  }

  return (
    <>
      <button onClick={handleClick}>
        Rédiger un commentaire
      </button>
      <Post ref={postRef} />
    </>
  );
}

Piège

N’abusez pas des refs. Vous ne devriez utiliser des refs que pour des comportements impératifs qui ne peuvent pas être exprimés par des props : faire défiler jusqu’à un nœud, activer un nœud, déclencher une animation, sélectionner un texte, et ainsi de suite.

Si vous pouvez exprimer quelque chose sous forme de prop, n’utilisez pas une ref. Par exemple, plutôt que d’exposer un objet impératif du genre { open, close } depuis un composant Modal, préférez proposer une prop isOpen pour une utilisation du style <Modal isOpen={isOpen} />. Les Effets peuvent vous aider à exposer des comportements impératifs au travers de props.