Is it safe to use React.forwardRef
method directly inside render function of another ponent -
Example -
function Link() {
// --- SOME EXTENSIVE LOGIC AND PROPS CREATING GOES HERE ---
// --- OMITTED FOR SIMPLICITY ---
// TO DO: Remove forward ref as soon Next.js bug will be fixed -
// .js/issues/7915
// Please note that Next.js Link ponent uses ref only to prefetch link
// based on its availability in view via IntersectionObserver API -
// .js/blob/canary/packages/next/client/link.tsx#L119
const TempShallow = React.forwardRef(props =>
cloneElement(child, {
...props,
...baseProps,
onClick: handleClick
})
);
return (
<NextLink href={href} as={as} prefetch={prefetch} passHref {...otherProps}>
<TempShallow />
</NextLink>
);
}
As you see it's a temporary workaround for a bug in Next.js v9 - .js/issues/7915.
Is it safe to use React.forwardRef
method directly inside render function of another ponent -
Example -
function Link() {
// --- SOME EXTENSIVE LOGIC AND PROPS CREATING GOES HERE ---
// --- OMITTED FOR SIMPLICITY ---
// TO DO: Remove forward ref as soon Next.js bug will be fixed -
// https://github./zeit/next.js/issues/7915
// Please note that Next.js Link ponent uses ref only to prefetch link
// based on its availability in view via IntersectionObserver API -
// https://github./zeit/next.js/blob/canary/packages/next/client/link.tsx#L119
const TempShallow = React.forwardRef(props =>
cloneElement(child, {
...props,
...baseProps,
onClick: handleClick
})
);
return (
<NextLink href={href} as={as} prefetch={prefetch} passHref {...otherProps}>
<TempShallow />
</NextLink>
);
}
As you see it's a temporary workaround for a bug in Next.js v9 - https://github./zeit/next.js/issues/7915.
Share Improve this question asked Aug 3, 2019 at 10:24 KosmetikaKosmetika 21.3k38 gold badges112 silver badges177 bronze badges 1-
I've missed a thing about reconciliation for
forwardRef
, check update in my answer – skyboyer Commented Aug 3, 2019 at 10:54
2 Answers
Reset to default 9Beware forwardRef
affects reconciliation: element is always re-created on parent re-rendering.
Say
function App() {
const [,setState] = useState(null);
const Input = React.forwardRef((props, ref) => <input {...props} />)
return (
<div className="App">
<h1>Input something into inputs and then click button causing re-rendering</h1>
<Input placeholder="forwardRef" />
<input placeholder="native" />
<button onClick={setState}>change state to re-render</button>
</div>
);
}
You may see that after clicking button forwardRef
-ed input is dropped and re-created so it's value bees empty.
Not sure if this could be important for <Link>
but in general it means things you'd expect to run only once per life time(say fetching data in ponentDidMount
or useEffect(...,[])
as alternative) will happen much more frequently.
So if choosing between this side effect and mocking warning I'd rather ignore Warning. Or create own <Link >
that will not cause warnings.
[UPD] missed one thing: React checks forwardRef
by reference in this case. So if you make forwardRef
out of the render
(so it's referentially the same) it will not be recreated:
const Input = React.forwardRef((props, ref) => <input {...props} />)
function App() {
const [,setState] = useState(null);
return (
<div className="App">
<h1>Input something into inputs and then click button causing re-rendering</h1>
<Input placeholder="forwardRef" />
<input placeholder="native" />
<button onClick={setState}>change state to re-render</button>
</div>
);
}
But still I believe it's safer to ignore warning than to introduce such a workaround.
Code above has worse readability to me and is confusing("why ref
is not processed at all? was it intentional? why this forwardRef
is here and not in ponent's file?")
I concurr with skyboyer, I'll add that it might be possible to create the forwardRef
ponent outside of the render function to avoid re-creating the ponent each render. To be checked.
const TempShallow = React.forwardRef(({ child, ...props }) => React.cloneElement(child, props))
function Link() {
// --- SOME EXTENSIVE LOGIC AND PROPS CREATING GOES HERE ---
// --- OMITTED FOR SIMPLICITY ---
// TO DO: Remove forward ref as soon Next.js bug will be fixed -
// https://github./zeit/next.js/issues/7915
// Please note that Next.js Link ponent uses ref only to prefetch link
// based on its availability in view via IntersectionObserver API -
// https://github./zeit/next.js/blob/canary/packages/next/client/link.tsx#L119
return (
<NextLink href={href} as={as} prefetch={prefetch} passHref {...otherProps}>
<TempShallow {...props} {...baseprops} child={child} onClick={onClick} />
</NextLink>
)
}