forwardRef

forwardRef rajapinnan avulla komponentti voi tarjota DOM noodin pääkomponenetille ref:llä.

const SomeComponent = forwardRef(render)

Viite

forwardRef(render)

Kutsu forwardRef() -funktiota, jotta komponenttisi voi vastaanottaa ref:n ja välittää sen lapsikomponentille:

import { forwardRef } from 'react';

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

Katso lisää esimerkkejä alla.

Parametrit

  • render: Komponenttisi renderöintifunktio. React kutsuu tätä funktiota komponentin pääkomponentilta saamilla propseilla ja ref:lla. JSX, jonka palautat, on komponenttisi ulostulo.

Palautukset

forwardRef palauttaa React-komponentin, jonka voit renderöidä JSX:llä. Toisin kuin React-komponentit, jotka on määritelty tavallisina funktioina, forwardRef:n palauttama komponentti voi myös vastaanottaa ref propin.

Huomiot

  • Strict Modessa, React kutsuu renderöintifunktiotasi kahdesti auttaakseen sinua löytämään tahattomia epäpuhtauksia. Tämä on vain kehitystilassa tapahtuva käyttäytyminen, eikä vaikuta tuotantoon. Jos renderöintifunktiosi on puhdas (kuten sen pitäisi olla), tämä ei vaikuta komponenttisi logiikkaan. Toinen kutsuista jätetään huomiotta.

render funktio

forwardRef hyväksyy renderöintifunktion argumenttina. React kutsuu tätä funktiota props ja ref -argumenteilla:

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

Parametrit

  • props: Propsit, jotka pääkomponentti on välittänyt.

  • ref: ref attribuutti, jonka pääkomponentti on välittänyt. ref voi olla joko objekti tai funktio. Jos pääkomponentti ei ole välittänyt ref:iä, se on null. Sinun tulisi joko välittää saamasi ref toiselle komponentille tai välittää se useImperativeHandle:lle.

Palautukset

forwardRef palauttaa React komponentin, jonka voit renderöidä JSX:llä. Toisin kuin React komponentit, jotka on määritelty tavallisina funktioina, forwardRef:n palauttama komponentti voi myös vastaanottaa ref propin.


Käyttö

DOM noodin välittäminen pääkomponentille

Oletuksena jokaisen komponentin DOM noodit ovat yksityisiä. Joskus on kuitenkin hyödyllistä välittää DOM noodi pääkomponentille, esimerkiksi mahdollistaaksesi siihen kohdentamisen. Ottaaksesi tämän käyttöön, kääri komponenttisi forwardRef() -funktioon:

import { forwardRef } from 'react';

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

Saat ref -argumentin toisena argumenttina propsien jälkeen. Välitä se DOM noodiin, jonka haluat julkaista:

import { forwardRef } from 'react';

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

Tämän avulla pääkomponentti Form voi käyttää MyInput komponentin julkaisemaa <input> DOM noodia:

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

Form komponentti välittää ref:n MyInput:lle. MyInput komponentti välittää sen ref:n <input> selaimen tagille. Tämän seurauksena Form komponentti voi käyttää <input> DOM noodia ja kutsua focus() siihen.

Pidä mielessä, että ref:n julkaiseminen komponenttisi sisällä olevaan DOM noodin tekee sen vaikeammaksi muuttaa komponenttisi sisäistä rakennetta myöhemmin. Yleensä julkaiset DOM noodin ref:n uudelleen käytettävistä matalan tason komponenteista, kuten painikkeista tai tekstisyötteistä, mutta et tee sitä sovellustason komponenteille, kuten avatarille tai kommentille.

Examples of forwarding a ref

Esimerkki 1 / 2:
Syöttökenttään kohdistaminen

Painiketta painaminen kohdistaa syöttökenttään. Form komponentti määrittelee ref:n ja välittää sen MyInput komponentille. MyInput komponentti välittää sen ref:n selaimen <input> tagille. Tämän avulla Form komponentti voi kohdistaa <input>:in.

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


Refin välittäminen useiden komponenttien läpi

Sen sijaan, että välittäisit ref:n DOM noodille, voit välittää sen omalle komponentillesi kuten MyInput:

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

Jos tämä MyInput komponentti välittää ref:n <input>:lle, ref FormField:lle antaa sinulle tuon <input>:in:

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

Form komponentti määrittää refin ja välittää sen FormField:lle. FormField komponentti välittää tuon ref:n MyInput:lle, joka välittää sen selaimen <input> DOM noodille. Tämän avulla Form komponentti voi käsitellä tuota DOM noodia.

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


Imperatiivisen käsittelijän julkaiseminen DOM noden sijaan

Sen sijaan, että julkistaisit koko DOM noodin, voit julkistaa räätälöidyn olion, jota kutsutaan imperatiiviseksi käsittelijäksi, jolla on suppeampi joukko metodeja. Tämän toteuttamiseksi, sinun täytyy määrittää erillinen ref, joka pitää sisällään DOM noodin:

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

// ...

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

Välitä vastaanottamasi ref useImperativeHandle:lle ja määritä arvo, jonka haluat julkistaa ref:lle:

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

Jos jokin komponentti saa refin MyInput:lle, saa se vain { focus, scrollIntoView } olion koko DOM noodin sijaan. Tämän avulla voit rajoittaa DOM noodista julkistettavan informaation minimiin.

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

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

  function handleClick() {
    ref.current.focus();
    // Tämä ei toimi, koska DOM noodi ei ole julkistettu:
    // ref.current.style.opacity = 0.5;
  }

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

Lue lisää imperatiivisista käsittelijöistä.

Sudenkuoppa

Älä käytä ref:iä liikaa. Sinun tulisi käyttää ref:iä vain imperatiivisiin toimintoihin, joita et voi ilmaista propseina: esimerkiksi nodeen vierittäminen, noden kohdistaminen, animaation käynnistäminen, tekstin valitseminen jne.

Jos voit ilmaista jotain propseina, sinun ei tulisi käyttää ref:iä. Esimerkiksi sen sijaan, että julkistaisit Modal komponentista imperatiivisen käsittelijän kuten { open, close }, on parempi ottaa isOpen propsi kuten <Modal isOpen={isOpen} />. Efektit voivat auttaa sinua julkistamaan imperatiivisia toimintoja propseina.


Vianmääritys

Komponenttini on kääritty forwardRef:iin, mutta ref siihen on aina null

Usein tämä tarkoittaa, että unohdit käyttää ref:iä, jonka sait.

Esimerkiksi, tämä komponentti ei tee mitään sen ref:llä:

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

Korjataksesi tämän, välitä ref DOM noodille tai toiselle komponentille, joka voi vastaanottaa ref:n:

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

ref MyInput:lle voi olla myös null, jos osa logiikasta on ehdollista:

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

Jos showInput on false, ref:iä ei välitetä millekään nodille, ja ref MyInput:lle pysyy tyhjänä. Tämä on erityisen helppo jättää huomaamatta, jos ehto on piilotettu toisen komponentin sisälle, kuten Panel tässä esimerkissä:

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