Praca z elementami DOM w React

W tradycyjnym JavaScript, aby uzyskać dostęp do elementów modelu DOM, często sięga się po metodę getElementById, tak jak w poniższym przykładzie:

document.getElementById("ID_ELEMENTU");

Jednak w React, bezpośrednie manipulowanie elementami DOM w ten sposób nie jest zalecane. React zachęca do korzystania z podejścia deklaratywnego, gdzie to biblioteka zarządza aktualizacjami interfejsu użytkownika, a nie programista bezpośrednio przez JavaScript. Użycie getElementById i podobnych metod może prowadzić do konfliktów, ponieważ React może nie być świadomy zmian wprowadzonych poza jego systemem zarządzania stanem.

Co to jest useRef?

React oferuje rozwiązanie w postaci hooka useRef, który umożliwia zarówno dostęp do elementów DOM, jak i przechowywanie danych, które nie wywołują ponownego renderowania komponentu przy zmianie. Hook useRef zwraca obiekt z właściwością .current, w której przechowywana jest wartość referencji. Ta wartość jest „stała” przez cały cykl życia komponentu.

Dlaczego useRef jest użyteczny?

  • Dostęp do elementów DOM: Umożliwia interakcję z elementami DOM, np. ustawienie focusu na polu tekstowym, obsługę animacji czy zarządzanie formularzami.
  • Przechowywanie wartości: Zapewnia możliwość przechowywania danych przez cały cykl życia komponentu bez konieczności ponownego renderowania przy ich zmianie.

Przykład użycia useRef do pracy z elementem DOM

import React, { useRef } from 'react';

function App() {
  const inputEl = useRef(null);

  const onButtonClick = () => {
    inputEl.current.focus();
  };

  const onChangeEvent = () => {
    console.log("Zmiana inputa: ", inputEl.current.value);
  }

  return (
    <>
      <input ref={inputEl} type="text"  onChange={onChangeEvent} />
      <button onClick={onButtonClick}>Ustaw focus na input</button>
    </>
  );
}

export default App;

W tym przykładzie inputEl.current odnosi się do elementu input w DOM, co umożliwia wywołanie na nim metody focus() oraz innych metod z jego API.

Przykład użycia useRef do przechowywania danych

import React, { useRef } from 'react';

function App() {
  const countRef = useRef(0);

  const handleClick = () => {
    countRef.current += 1;
    console.log(`Przycisk kliknięty ${countRef.current} razy`);
  };

  return (
    <div>
      <button onClick={handleClick}>Kliknij mnie</button>
    </div>
  );
}

export default App;

I tutaj także musimy odwoływać się do właściwości current aby dostać się do przechowywanej wartości.

Przekazywanie refrencji między komponentami

React umożliwia przekazywanie referencji między komponentami, co jest szczególnie przydatne w przypadku konieczności bezpośredniej interakcji z elementem dziecka z poziomu komponentu rodzica.

Przykład

Komponent App przekazuje referencję do komponentu ChildInput, który z kolei używa forwardRef do odbioru tej referencji.

Komponent App:

import React, { useRef } from 'react';
import ChildInput from './ChildInput';

function App() {
  const inputRef = useRef();

  const focusChildInput = () => {
    inputRef.current.focus(); 
  };

  function handleChange() {
    console.log("Aktualna wartość inputa: ", inputRef.current.value);
  }

  return (
    <div>
      <ChildInput ref={inputRef} onChange={handleChange} className="form-input" />
      <button onClick={focusChildInput}>Fokus w komponencie dziecka</button>
    </div>
  );
}

export default App;

Oraz komponent ChildInput:

import React, { forwardRef } from 'react';

const ChildInput = forwardRef(({ onChange, className, children }, ref) => {
  return <input ref={ref} type="text" className={className} onChange={onChange} />;
});

export default ChildInput;

forwardRef umożliwia ChildInput przyjęcie ref od App, co umożliwia rodzicowi kontrolę nad elementem input dziecka.

useRef() vs useState()

Główna różnica między useRef a useState polega na tym, że aktualizacja referencji za pomocą useRef nie powoduje ponownego renderowania komponentu. Zmiany wartości przechowywanej w useRef są „ciche” dla cyklu renderowania Reacta. W przeciwieństwie do tego, useState zawsze wywołuje ponowne renderowanie przy zmianie stanu, co jest kluczowe dla aktualizacji interfejsu użytkownika.

Wartości przechowywane za pomocą useRef pozostają jednak niezmienione między renderowaniami, co jest przydatne do śledzenia wartości, które nie mają wpływać na wygląd komponentu.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *