In React 19, a long-awaited change has arrived -- passing
ref to function components has become much simpler! Just as new communication systems on our spaceships eliminate the need for complicated relays, React 19 eliminates the need to use forwardRef.In previous React versions, to pass a
ref to a child component, we had to use forwardRef:1import { forwardRef, useRef } from 'react';
2
3// Old way - requires 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// Usage
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 Start engines
24 </SpaceshipButton>
25 <button onClick={focusButton}>Focus on button</button>
26 </div>
27 );
28}In React 19,
ref is simply a regular prop! There is no need to use forwardRef:1import { useRef } from 'react';
2
3// New way in React 19 - ref is just a prop!
4function SpaceshipButton({ ref, children, ...props }) {
5 return (
6 <button ref={ref} className="spaceship-btn" {...props}>
7 {children}
8 </button>
9 );
10}
11
12// Usage - exactly the same!
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 Start engines
24 </SpaceshipButton>
25 <button onClick={focusButton}>Focus on button</button>
26 </div>
27 );
28}1// React 19 - simple input component
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 on first 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>Enter destination coordinates</h2>
29
30 <CoordinateInput
31 ref={latitudeRef}
32 label="Galactic latitude"
33 onKeyDown={handleLatitudeEnter}
34 />
35
36 <CoordinateInput
37 ref={longitudeRef}
38 label="Galactic longitude"
39 />
40
41 <button type="submit">Set course</button>
42 </form>
43 );
44}useImperativeHandle still works, but now without forwardRef:1import { useImperativeHandle, useRef } from 'react';
2
3function VideoPlayer({ ref, src }) {
4 const videoRef = useRef(null);
5
6 // Expose only selected methods
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 Your browser does not support video.
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 Play
35 </button>
36 <button onClick={() => playerRef.current?.pause()}>
37 Pause
38 </button>
39 <button onClick={() => playerRef.current?.seek(0)}>
40 From start
41 </button>
42 </div>
43 </div>
44 );
45}If you have existing code with
forwardRef, migration is straightforward:1// Before (React 18)
2const OldComponent = forwardRef(function OldComponent(props, ref) {
3 return <div ref={ref}>{props.children}</div>;
4});
5
6// After (React 19)
7function NewComponent({ ref, children }) {
8 return <div ref={ref}>{children}</div>;
9}
10
11// Usage remains identical!
12<OldComponent ref={myRef}>Old</OldComponent>
13<NewComponent ref={myRef}>New</NewComponent>React 19 introduces a significant simplification in ref forwarding:
This simplification makes components more predictable and easier to understand -- like modern space navigation systems that eliminate unnecessary complications!