GithubHelp home page GithubHelp logo

Refs merging/combining about react HOT 5 OPEN

FrameMuse avatar FrameMuse commented on July 27, 2024
Refs merging/combining

from react.

Comments (5)

monikkacha avatar monikkacha commented on July 27, 2024 2

That sounds depressing ๐Ÿ˜…, but I will still work on the feature and raise PR later on.

from react.

monikkacha avatar monikkacha commented on July 27, 2024 1

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.

from react.

FrameMuse avatar FrameMuse commented on July 27, 2024

@monikkacha

Here's two use-cases and my real-world example, hope this would be helpful.

Fallback

In React 19 I can use ref in props, put in an element and use it in the component itself while giving an outside access to it as well.

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 ref to be optional.

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 />

Concurrent

Concurrent happens when you have ref that is coming from a parent but your element also have a ref, you may say

Just use the ref that the parent is passing (-_-)/

This will actually work, but only in cases when the parent is passing an object.
If it's a callback, it won't work that easily, you will have to use useEffect to call passing ref, which is not ideal and may have consequences.

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 Example

I used TanStack Virtual to virtualize the list and I used ref to measure element dynamically, but I wanted the components of list to have possibility of click away.

In this case I had ref as a callback though components needed a ref object. It's somewhat close to a fallback case.

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

from react.

monikkacha avatar monikkacha commented on July 27, 2024

@eps1lon is it ok if i work on this issue and raise PR ?

from react.

eps1lon avatar eps1lon commented on July 27, 2024

Sure, but no promises when this will be reviewed or if it will be merged at all.

from react.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.