Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

React 19 - Nowy sposób przekazywania ref (bez forwardRef)

W React 19 nastąpiła długo oczekiwana zmiana - przekazywanie

ref
do komponentów funkcyjnych stało się znacznie prostsze! Podobnie jak nowe systemy komunikacji w naszych statkach kosmicznych eliminują potrzebę skomplikowanych przekaźników, React 19 eliminuje potrzebę używania
forwardRef
.

Stary sposób z forwardRef (React 18 i wcześniej)

W poprzednich wersjach Reacta, aby przekazać

ref
do komponentu potomnego, musieliśmy używać
forwardRef
:

1import { forwardRef, useRef } from 'react';
2
3// ❌ Stary sposób - wymaga forwardRef
4const SpaceshipButton = forwardRef((props, ref) => {
5  return (
6    <button ref={ref} className="spaceship-btn" {...props}>
7      {props.children}
8    </button>
9  );
10});
11
12// Użycie
13function MissionControl() {
14  const buttonRef = useRef(null);
15
16  const focusButton = () => {
17    buttonRef.current?.focus();
18  };
19
20  return (
21    <div>
22      <SpaceshipButton ref={buttonRef}>
23        Uruchom silniki
24      </SpaceshipButton>
25      <button onClick={focusButton}>Fokus na przycisk</button>
26    </div>
27  );
28}

Nowy sposób w React 19 - ref jako prop

W React 19

ref
jest po prostu zwykłym propem! Nie ma potrzeby używania
forwardRef
:

1import { useRef } from 'react';
2
3// ✅ Nowy sposób w React 19 - ref to po prostu prop!
4function SpaceshipButton({ ref, children, ...props }) {
5  return (
6    <button ref={ref} className="spaceship-btn" {...props}>
7      {children}
8    </button>
9  );
10}
11
12// Użycie - dokładnie tak samo!
13function MissionControl() {
14  const buttonRef = useRef(null);
15
16  const focusButton = () => {
17    buttonRef.current?.focus();
18  };
19
20  return (
21    <div>
22      <SpaceshipButton ref={buttonRef}>
23        Uruchom silniki
24      </SpaceshipButton>
25      <button onClick={focusButton}>Fokus na przycisk</button>
26    </div>
27  );
28}

Praktyczne przykłady

1. Input z auto-focus

1// ✅ React 19 - prosty komponent inputa
2function CoordinateInput({ ref, label, ...props }) {
3  return (
4    <div className="coordinate-field">
5      <label>{label}</label>
6      <input ref={ref} {...props} />
7    </div>
8  );
9}
10
11function NavigationPanel() {
12  const latitudeRef = useRef(null);
13  const longitudeRef = useRef(null);
14
15  useEffect(() => {
16    // Auto-focus na pierwszy input
17    latitudeRef.current?.focus();
18  }, []);
19
20  const handleLatitudeEnter = (e) => {
21    if (e.key === 'Enter') {
22      longitudeRef.current?.focus();
23    }
24  };
25
26  return (
27    <form className="nav-panel">
28      <h2>Wprowadź współrzędne docelowe</h2>
29
30      <CoordinateInput
31        ref={latitudeRef}
32        label="Szerokość galaktyczna"
33        onKeyDown={handleLatitudeEnter}
34      />
35
36      <CoordinateInput
37        ref={longitudeRef}
38        label="Długość galaktyczna"
39      />
40
41      <button type="submit">Ustaw kurs</button>
42    </form>
43  );
44}

useImperativeHandle - nadal użyteczny

useImperativeHandle
nadal działa, ale teraz bez
forwardRef
:

1import { useImperativeHandle, useRef } from 'react';
2
3function VideoPlayer({ ref, src }) {
4  const videoRef = useRef(null);
5
6  // Eksponuj tylko wybrane metody
7  useImperativeHandle(ref, () => ({
8    play: () => videoRef.current?.play(),
9    pause: () => videoRef.current?.pause(),
10    seek: (time) => {
11      if (videoRef.current) {
12        videoRef.current.currentTime = time;
13      }
14    },
15    getCurrentTime: () => videoRef.current?.currentTime || 0,
16  }), []);
17
18  return (
19    <video ref={videoRef} src={src} className="space-video">
20      Twoja przeglądarka nie obsługuje wideo.
21    </video>
22  );
23}
24
25function MediaController() {
26  const playerRef = useRef(null);
27
28  return (
29    <div>
30      <VideoPlayer ref={playerRef} src="/space-documentary.mp4" />
31
32      <div className="controls">
33        <button onClick={() => playerRef.current?.play()}>
34          ▶ Odtwórz
35        </button>
36        <button onClick={() => playerRef.current?.pause()}>
37          ⏸ Pauza
38        </button>
39        <button onClick={() => playerRef.current?.seek(0)}>
40          ⏮ Od początku
41        </button>
42      </div>
43    </div>
44  );
45}

Migracja z forwardRef

Jeśli masz istniejący kod z

forwardRef
, migracja jest prosta:

1// ❌ Przed (React 18)
2const OldComponent = forwardRef(function OldComponent(props, ref) {
3  return <div ref={ref}>{props.children}</div>;
4});
5
6// ✅ Po (React 19)
7function NewComponent({ ref, children }) {
8  return <div ref={ref}>{children}</div>;
9}
10
11// Użycie pozostaje identyczne!
12<OldComponent ref={myRef}>Stary</OldComponent>
13<NewComponent ref={myRef}>Nowy</NewComponent>

Podsumowanie

React 19 wprowadza znaczące uproszczenie w przekazywaniu referencji:

  1. ref jest zwykłym propem - nie wymaga specjalnego traktowania
  2. forwardRef jest deprecated - nadal działa, ale zalecana migracja
  3. useImperativeHandle działa bez forwardRef - przekaż ref jako prop
  4. Callback refs bez zmian - działają tak samo jak wcześniej
  5. TypeScript - ref ma teraz typ w props, nie wymaga specjalnej obsługi

To uproszczenie sprawia, że komponenty są bardziej przewidywalne i łatwiejsze do zrozumienia - jak nowoczesne systemy nawigacji kosmicznej, które eliminują zbędne komplikacje!

Przejdź do CodeWorlds