Files
35f60806d7 Re-enable legacyBehavior and passHref on Link (#84500)
In https://github.com/vercel/next.js/pull/83003, `legacyBehavior` and
`passHref` were removed from `<Link>`. However, this turned out to be a
bit premature—despite most usage being covered by the newer `<Link>`
APIs, there's some use cases we don't yet have good alternatives for.

We expect to solve this with an API that uses Fragment Refs once they're
available in React. For now, we're re-enabling these flags.

---------

Co-authored-by: JJ Kasper <[email protected]>
2025-10-08 16:37:36 -07:00

87 lines
2.0 KiB
TypeScript

'use client'
import Link from 'next/link'
import {
useCallback,
useState,
type ComponentPropsWithRef,
type ReactNode,
type Ref,
type RefCallback,
} from 'react'
export default function Page() {
return (
<>
<h1>Home</h1>
<ToggleVisibility>
<Link href="/link-target" legacyBehavior>
<AnchorThatDoesRefMerging id="test-link">
Go to /link-target
</AnchorThatDoesRefMerging>
</Link>
</ToggleVisibility>
</>
)
}
function ToggleVisibility({ children }: { children: ReactNode }) {
const [isVisible, setIsVisible] = useState(true)
return (
<>
<div>
<button type="button" onClick={() => setIsVisible((prev) => !prev)}>
{isVisible ? 'Hide content' : 'Show content'}
</button>
</div>
{isVisible ? children : null}
</>
)
}
function AnchorThatDoesRefMerging({
ref,
children,
...anchorProps
}: ComponentPropsWithRef<'a'>) {
const customRef: RefCallback<HTMLAnchorElement> = useCallback((el) => {
if (el) {
console.log('hello friends i am here')
} else {
console.log('goodbye friends i am gone')
}
}, [])
const finalRef = useBuggyRefMerge(customRef, ref ?? null)
return (
<a ref={finalRef} {...anchorProps}>
{children}
</a>
)
}
/** A ref-merging function that doesn't account for cleanup refs (added in React 19)
* https://react.dev/blog/2024/12/05/react-19#cleanup-functions-for-refs
*/
function useBuggyRefMerge<TElement>(
refA: Ref<TElement>,
refB: Ref<TElement>
): RefCallback<TElement> {
return useCallback(
(current: TElement | null) => {
for (const ref of [refA, refB]) {
if (!ref) {
continue
}
if (typeof ref === 'object') {
ref.current = current
} else {
// BUG!!!
// This would work in 18, but in 19 it can return a cleanup which will get swallowed here
ref(current)
}
}
},
[refA, refB]
)
}