Nie wspominałem o tym, bo wydawało mi się to oczywiste, ale tak jak propsy możemy przekazywać w dół w jedynym słusznym kierunku przez wiele komponentów, to samo możemy robić z forwardRef.

Oto komponent najniższy:

import { forwardRef } from 'react';

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

export default MyInput;

Dlatego najniższy, bo jego forwardRef jest forwardowane do czegoś, co można najogólniej opisać jako obiekt klasy HTMLElement a nie RFC.

Teraz komponent wyżej, komponent pośrednik:

import { forwardRef, useState } from 'react';
import MyInput from './MyInput.js';

const FormField = forwardRef(function FormField({ label, isRequired }, ref) {
  const [value, setValue] = useState('');
  return (
    <>
      <MyInput
        ref={ref}
        label={label}
        value={value}
        onChange={e => setValue(e.target.value)} 
      />
      {(isRequired && value === '') &&
        <i>Required</i>
      }
    </>
  );
});

export default FormField;

Dlatego pośrednik, bo choć przypisuje ref do nieelementu RFC, który forwarduje to dalej, to sam żadnego ref nie tworzy tylko sam od rodzica przyjmuje i forwarduje.

Oto rodzic:

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

Wydaje mi się oczywiste, co tu się dzieje. Widzieliśmy już, jak można propsy przekazywać z góry w dół, to samo mamy z refami. Może na początku trochę to podchwytliwe, ale bez przesady.

Może gdyby tak do tego przykładu wprowadzić useImperativeHandle dla komponentu najniższego, to zrobiłoby się trudniej, ale przynajmniej ciekawiej, moglibyśmy zrozumieć już w pełni i pozbierać do kupy naszą wiedzę o refach.

Zostawiam to jako potencjalne zadanie domowe – robimy wielopoziomowe refy + useImperativeHandle.

Więcej Reacta niedługo…