React-popper: miss being able to set a custom component

Created on 25 Apr 2017  路  15Comments  路  Source: popperjs/react-popper

using a function is nice, but because of the ref I need to make sure the child component is not a functional component, which at times means I need to have an extra node in the dom that may or may not mess with styling, etc.

Most helpful comment

You might be able to use something like @P8TRO's answer above with React.cloneElement and React.findDOMNode. Contrived version might look like:

const ToolTip = ({ children }) => (
    ...
    <Reference>
      {({ ref }) =>
        React.cloneElement(
          React.Children.only(children),
          { ref: component => ref(React.findDOMNode(component)) }
        )
      }
    </Reference>
    ...
)

But I'd really try to use explicit refs like @FezVrasta described.

All 15 comments

Can you provide an example? I don't like unnecessary DOM nodes, so I'd like to try and fix this :)

What's wrong with the method I have you on Twitter? It didn't need any additional wrapper

so for example I need to let Target render a div or I need make sure the component within a popper is a Class Component. I do a lot of layout with flexbox, so having a non-flex div in the middle of things can potentially cause issues.

In 0.4.3 I was able to do the following:

<Target component={null}>
  <Button label="button" onClick={this.togglePopover} />
</Target>

Still confused on how another DOM node is created? Does the ref from a child function not work here?

all my potential child components are functional and you can't use refs with functional components.

https://facebook.github.io/react/docs/refs-and-the-dom.html#refs-and-functional-components

That being said, maybe I could look into making my own wrapper component that can consume the ref without adding a dom node...

As long as the functional component returns an element and it gets the ref passed to it, it will work fine. The update I'm working on might solve this since it will group the ref into the props now rather than having the popperRef.

I'm just saying because my Button component is functional (for example) it can't consume a ref:

function Button({label}) {
  return <button>{label}</button>
}

so I can't use it within popper without first wrapping it in a Class based component. (or just letting Popper create a div)

Ahh I see. If you are the creator of the button you could give access to the ref by doing something like:

function Button({label, innerRef}) {
  return <button ref={innerRef}>{label}</button>
}

Going to close this since we can't bring component back 馃拃 but please let me know if you have any other questions regarding this thread.

Ooh, how did I not think of this! This solves all sorts of problems! 馃帄

sorry, but if I use third-party components, which not have ref attribute, how can I put that component to Target?

@mozartilize this is what I came up with. Unfortunately it doesn't work with functional components (still trying to find a workaround) but accommodates everything else

<CustomPopperWrapper>
  <div className="target"/>
  <div className="tooltip"/>
</CustomPopperWrapper>

...

<Target key="target">
    {({ targetProps }) =>
        React.cloneElement(children[0], {
            ref: node => {
                // popper.js requires a DOM reference - if you pass it as a direct child, custom components get an extra div wrapper.
                // this allows regular consumers to pass whatever children they want while eliminated the extra div. and maintaining an original ref
                if (_.isFunction(children[0].ref)) children[0].ref(node)
                // eslint-disable-next-line react/no-find-dom-node
                targetProps.ref(ReactDOM.findDOMNode(node))
                this.target = node
            },
        })
    }
</Target>

react-tether refugee here - @FezVrasta @souporserious I really appreciate the work you've both put into these libraries. Thank you thank you 馃槃

Hate to rewake an old issue, but just wondering if there is any way to handle this ref vs innerRef question in the v1.0.0 api?

I'm struggling to write a generic Tooltip component because I'm not sure if there is a clear way to determine when to use ref or innerRef. That is, a clear way to determine which to use from the tooltip component itself.

Here's how I'd like to use the tooltip:

// This tooltip takes a regular span element as the reference
<Tooltip text="Popup text">
  <span>Span</span>
</Tooltip>

// This tooltip takes a styled component.
// The example uses styled components because they use innerRef instead of ref.
<Tooltip text="Popup text">
  <StyledSpan>Span</StyledSpan>
</Tooltip>

Can this be done using react-popper without adding extra DOM nodes?

I suppose the other option is to just pass an extra prop like so:

<Tooltip text="Popup text" useInnerRef>
  <StyledSpan>Span</StyledSpan>
</Tooltip>

Rather not do this though...

@souporserious Any advice on writing a generic tooltip like this?

innerRef is just a convention, a component may use any property to expose its inner ref, or just use ref directly with the new React.forwardRef helper.

~So there's not a way to know it without some hint from the user.~

You might be able to use something like @P8TRO's answer above with React.cloneElement and React.findDOMNode. Contrived version might look like:

const ToolTip = ({ children }) => (
    ...
    <Reference>
      {({ ref }) =>
        React.cloneElement(
          React.Children.only(children),
          { ref: component => ref(React.findDOMNode(component)) }
        )
      }
    </Reference>
    ...
)

But I'd really try to use explicit refs like @FezVrasta described.

Okay, got it. Thanks guys. Much appreciated :)

Has there been any more work done on the ideas mentioned in https://github.com/FezVrasta/react-popper/issues/79? I liked your idea of using ids. Seems to be a solid way to get around these ref complications.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

gormonn picture gormonn  路  4Comments

souporserious picture souporserious  路  6Comments

RajaBellebon picture RajaBellebon  路  3Comments

Argonanth picture Argonanth  路  4Comments

linusthe3rd picture linusthe3rd  路  4Comments