メインコンテンツまでスキップ

「react19」タグの記事が1件件あります

全てのタグを見る

React 19 Ref

· 約3分
Mikyan
白い柴犬

In React 19, ref can directly be passed to a component as a property, and forwardRef become unrecommanded.

About ref

In React, a ref (reference) let you operate lower-level imperative API on the following elements:

  • DOM nodes
  • Class component instances

Usually it is created with useRef hook.

function Chat() {
const endRef = useRef();
useEffect(() => {
endRef.current.scrollIntoView({ behavior: 'smooth' });
}, [messages]);
return (
<div className="chat-window">
{messages.map(m => <Message key={m.id} />)}
<div ref={endRef} />
</div>
);
}

Sometimes we need to pass ref down to point to one component of a child component, below are suitable situations:

  • When you build a HOC component
  • When you wrapping a core component with customized design (like wrapping a material UI Input)

Note that usually it is not a good practice, since it increase the complicity and voilate the capsluating philosoph, we should be careful about the usecases.

Improved ref API in React.19

Before React 19, it is not allowed to pass ref as a property, Instead, forwardRef is needed:

import React, { forwardRef, useRef, useImperativeHandle } from 'react';

const FancyInput = forwardRef(function FancyInput(_, ref) {
const inputRef = useRef();

useImperativeHandle(ref, () => ({
focus: () => inputRef.current?.focus(),
clear: () => { if (inputRef.current) inputRef.current.value = ''; }
}), []);

return <input ref={inputRef} className="border rounded p-2" />;
});

export default FancyInput;

// Parent.jsx
import React, { useRef } from 'react';
import FancyInput from './FancyInput';

function Parent() {
const fancyRef = useRef();

return (
<>
<FancyInput ref={fancyRef} />
<button onClick={() => fancyRef.current.focus()}>Focus</button>
<button onClick={() => fancyRef.current.clear()}>Clear</button>
</>
);
}

Note in the example, useImperativeHandle is used to defines the customer handler of ref. By declaring useImperativeHandle in the component, we can:

  • rewrite the ref handler behavior
  • safely limit the handlers of the ref

By using useImperativeHandle, the original ref donot directly pass to the input, instead in the component we define a new ref, to let the ref operates indirectly.

However, from React 19, forwardRef is not recommended, and ref can be passed directly, which is more concise and have better readability:

import React, { forwardRef, useRef, useImperativeHandle } from 'react';

function FancyInput({ ref }) {
const inputRef = useRef();

useImperativeHandle(ref, () => ({
focus: () => inputRef.current?.focus(),
clear: () => { if (inputRef.current) inputRef.current.value = ''; }
}), []);

return <input ref={inputRef} className="border rounded p-2" />;
});

export default FancyInput;

// Parent.jsx
import React, { useRef } from 'react';
import FancyInput from './FancyInput';

function Parent() {
const fancyRef = useRef();

return (
<>
<FancyInput ref={fancyRef} />
<button onClick={() => fancyRef.current.focus()}>Focus</button>
<button onClick={() => fancyRef.current.clear()}>Clear</button>
</>
);
}