-
Notifications
You must be signed in to change notification settings - Fork 45.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refs merging/combining #29757
Comments
Hey @FrameMuse, I checked your reference npm package and whole scenario and it seems like worth adding, but I haven't gotten around to such a scenario as when I need to have a ref for parent and child both component, can you please explain the use case further more so I can better understand the requirement. I am willing to work on this feature and raise PR if the scenario is really useful and maintainers are happy to add this feature. |
Here's two use-cases and my real-world example, hope this would be helpful. FallbackIn React 19 I can use function Component(props: { ref: Ref<HTMLDivElement> }) {
useClickAway(props.ref)
return <div ref={props.ref} />
}
function Parent() {
const elementRef = useRef<HTMLDivElement>(null)
useLayoutEffect(() => {
elementRef.current.clientHeight // Will actually work now.
}, [])
return <Component ref={elementRef} />
} But the problem comes when you want to make that function Component(props: { ref?: Ref<HTMLDivElement> }) {
useClickAway(props.ref) // Won't work if `ref` is not passed.
return <div ref={props.ref} />
}
// Click Away will work only for component that is receiving a ref.
<Component ref={elementRef} />
<Component /> That's why we need to use a fallback ref. function Component(props: { ref?: Ref<HTMLDivElement> }) {
const elementRef = useRef<HTMLDivElement>(null)
const combinedRef = combineRefs([elementRef , props.ref])
useClickAway(elementRef) // Now will work regardless of passed `ref`.
return <div ref={combinedRef} />
}
// Click Away will work for both components.
<Component ref={elementRef} />
<Component /> ConcurrentConcurrent happens when you have ref that is coming from a parent but your element also have a ref, you may say
This will actually work, but only in cases when the parent is passing an object. To solve it, you will need to pass a callback to the element and call or assign your refs. That's why there is a library that provides a function for that. Real-World ExampleI used TanStack Virtual to virtualize the list and I used In this case I had interface ItemsProps {
items: object[]
}
function Items(props: ItemsProps) {
const elementRef = useRef<HTMLDivElement>(null)
const scrolling = useContext(scrollingContext)
const virtual = useVirtualizer({
count: props.items.length,
gap: 8,
getScrollElement: () => scrolling.elementRef.current,
estimateSize: () => 60,
measureElement: element => element.scrollHeight,
overscan: 5
})
const items = virtual.getVirtualItems()
return (
<div className="items" style={{ height: virtual.getTotalSize(), zIndex: 0 }} ref={elementRef}>
{items.map(item => (
<div style={{ height: item.size, transform: `translateY(${item.start}px)`, zIndex: -item.index }} key={item.key}>
<Item {...props.items[item.index]} index={item.index} ref={virtual.measureElement} />
</div>
))}
</div>
)
}
interface ItemProps {
index: number
ref?: Ref<HTMLDivElement>
}
function Item(props: ItemProps) {
const elementRef = useRef<HTMLDivElement>(null)
const combinedRef = combineRefs([elementRef, props.ref])
const [expanded, setExpanded] = useState(false)
useClickAway(elementRef, () => setExpanded(false))
return <div onClick={() => setExpanded(true)} ref={combinedRef} />
} The code is simplified and generalized to not disclose any source code |
@eps1lon is it ok if i work on this issue and raise PR ? |
Sure, but no promises when this will be reviewed or if it will be merged at all. |
That sounds depressing 😅, but I will still work on the feature and raise PR later on. |
Summary
I wanted to use
ref
fromprops
while also creating a localref
as a fallback, but I got into this problem #17200.I know this could be resolved with a little code, though I think this behavior should belong natively to React. There is even a package for that https://www.npmjs.com/package/react-merge-refs with ~1 million downloads/week, which confirms necessity of this for the React users.
I would propose something like
or at least this for fallback cases
or hook/helper to resolve
ref
s concurrencyWhat do you think? Am I going too far with it? 😅
The text was updated successfully, but these errors were encountered: