forwardRef memungkinkan Anda mengekspos sebuah simpul DOM sebagai sebuah ref kepada induknya.

const SomeComponent = forwardRef(render)

Referensi

forwardRef(render)

Panggil fungsi forwardRef() untuk membiarkan komponen Anda menerima ref dan meneruskannya ke komponen anak:

import { forwardRef } from 'react';

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

[Lihat contoh lainnya di bawah ini.] (#usage)

Parameter

  • render: Fungsi render untuk komponen Anda. React memanggil fungsi ini dengan props dan ref yang diterima komponen Anda dari induknya. JSX yang Anda kembalikan akan menjadi keluaran dari komponen Anda.

Kembalian

forwardRef mengembalikan komponen React yang dapat Anda render di JSX. Tidak seperti komponen React yang didefinisikan sebagai fungsi biasa, komponen yang dikembalikan oleh forwardRef juga dapat menerima prop ref.

Peringatan

  • Dalam Mode Ketat, React akan memanggil fungsi render Anda dua kali untuk membantu Anda menemukan ketidakmurnian yang tidak disengaja. Ini adalah perilaku khusus pengembangan dan tidak mempengaruhi produksi. Jika fungsi render Anda murni (sebagaimana mestinya), hal ini tidak akan mempengaruhi logika komponen Anda. Hasil dari salah satu pemanggilan akan diabaikan.

render function

forwardRef menerima fungsi render sebagai argumen. React memanggil fungsi ini dengan props dan ref:

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

Parameter

  • props: props yang dioperkan oleh komponen induk.

  • ref: Atribut ref yang dioper oleh komponen induk. ref dapat berupa objek atau fungsi. Jika komponen induk tidak mengoper ref, maka akan menjadi null. Anda harus mengoper ref yang Anda terima ke komponen lain, atau mengopernya ke useImperativeHandle.

Kembalian

forwardRef mengembalikan komponen React yang dapat Anda render di JSX. Tidak seperti komponen React yang didefinisikan sebagai fungsi biasa, komponen yang dikembalikan oleh forwardRef dapat mengambil sebuah prop ref.


Penggunaan

Mengekspos sebuah simpul DOM ke komponen induk

Secara default, simpul-simpul DOM dari setiap komponen bersifat privat. Namun, terkadang berguna untuk mengekspos simpul DOM ke induknya - misalnya, untuk memungkinkan pemfokusan. Untuk ikut serta, bungkus definisi komponen Anda ke dalam forwardRef():

import { forwardRef } from 'react';

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

Anda akan menerima ref sebagai argumen kedua setelah props. Berikan ke simpul DOM yang ingin Anda ekspos:

import { forwardRef } from 'react';

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

Hal ini memungkinkan komponen Form induk mengakses <input> DOM node yang diekspos oleh 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>
);
}

Komponen MyInput meneruskan ref tersebut ke tag peramban <input>. Hasilnya, komponen Form dapat mengakses simpul DOM <input> tersebut dan memanggil fungsi focus() di atasnya.

Perlu diingat bahwa mengekspos ref ke simpul DOM di dalam komponen Anda akan mempersulit untuk mengubah internal komponen Anda di kemudian hari. Anda biasanya akan mengekspos simpul DOM dari komponen tingkat rendah yang dapat digunakan kembali seperti tombol atau input teks, tetapi Anda tidak akan melakukannya untuk komponen tingkat aplikasi seperti avatar atau komentar.

Try out some examples

Example 1 of 2:
Memfokuskan input teks

Mengeklik tombol akan memfokuskan input. Komponen Form mendefinisikan sebuah ref dan meneruskannya ke komponen MyInput. Komponen MyInput meneruskan ref tersebut ke tag peramban <input>. Hal ini memungkinkan komponen Form memfokuskan <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>
  );
}


Meneruskan ref melalui beberapa komponen

Alih-alih meneruskan ref ke DOM node, Anda bisa meneruskannya ke komponen Anda sendiri seperti MyInput:

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

Jika komponen MyInput meneruskan sebuah ref ke <input>, sebuah ref ke FormField akan memberi Anda <input> tersebut:

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

Komponen Form mendefinisikan sebuah ref dan meneruskannya ke FormField. Komponen FormField meneruskan ref tersebut ke MyInput, yang meneruskannya ke DOM node <input> peramban. Beginilah cara Form mengakses DOM node tersebut.

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


Mengekspos penanganan imperatif alih-alih sebuah simpul DOM

Daripada mengekspos seluruh simpul DOM, Anda dapat mengekspos objek khusus, yang disebut penanganan imperatif (imperative handle), dengan sekumpulan methods yang lebih terbatas. Untuk melakukan ini, Anda harus mendefinisikan ref terpisah untuk menampung DOM node:

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

// ...

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

Berikan ref yang Anda terima ke useImperativeHandle dan tentukan nilai yang ingin Anda ekspos ke 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} />;
});

Jika beberapa komponen mendapatkan referensi ke MyInput, komponen tersebut hanya akan menerima objek { focus, scrollIntoView }, bukan simpul DOM. Hal ini memungkinkan Anda membatasi informasi yang Anda paparkan tentang simpul DOM seminimal mungkin.

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

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

  function handleClick() {
    ref.current.focus();
    // This won't work because the DOM node isn't exposed:
    // ref.current.style.opacity = 0.5;
  }

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

Baca lebih lanjut tentang menggunakan penanganan imperatif.

Pitfall

Jangan terlalu sering menggunakan refs. Anda hanya boleh menggunakan refs untuk perilaku imperatif yang tidak dapat Anda ungkapkan sebagai props: misalnya, menggulir ke sebuah simpul, memfokuskan sebuah simpul, memicu sebuah animasi, memilih teks, dan sebagainya.

Jika Anda dapat mengekspresikan sesuatu sebagai prop, Anda tidak seharusnya menggunakan ref. Sebagai contoh, alih-alih mengekspos sebuah penanganan imperatif seperti { open, close } dari sebuah komponen Modal, lebih baik menggunakan isOpen sebagai prop seperti <Modal isOpen={isOpen} />. Efek dapat membantu Anda mengekspos perilaku imperatif melalui props.


Pemecahan Masalah

Komponen saya dibungkus dengan forwardRef, tetapi ref ke komponen tersebut selalu null

Hal ini biasanya berarti bahwa Anda lupa menggunakan ref yang Anda terima.

Sebagai contoh, komponen ini tidak melakukan apa pun dengan ref-nya:

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

Untuk memperbaikinya, berikan ref ke simpul DOM atau komponen lain yang dapat menerima ref:

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

ref ke Komponen MyInput juga dapat menjadi null jika beberapa logika bersyarat:

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

Jika showInput bernilai false, maka ref tidak akan diteruskan ke simpul mana pun, dan ref ke MyInput akan tetap kosong. Hal ini sangat mudah terlewatkan jika kondisi tersebut tersembunyi di dalam komponen lain, seperti Panel pada contoh ini:

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