2
votes

What I want to achieve is to render a ReactPortal inside a ref, thus inside the React Application itself, and not a DOM node outside.

I've made a sort of example on Codepen -> https://codepen.io/Gesma94/pen/RqKZmM

class Legend extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    if (this.props.useRef)
      return ReactDOM.createPortal(<div className="legend">Something</div>, this.props.ref);
    else
      return <div className="legend">Something else</div>;
  }
}

class Chart extends React.Component {
  private myref;

  render() {
        return (
      <div>
        <div className="container" ref={r => this.myref = r}>First Container</div>
        <Legend ref={this.myref} useRef={false} />
      </div>
    );
  }
}

ReactDOM.render(<Chart />, document.getElementById('root'));

So, basically: inside Chart Component I save the ref of the first div, and then I pass that ref to the Legend Component. Inside the Legend Component, if the props useRef is true, I want to use the createPortal() to return a div inside the Chart's div.

The problem is that React throw me error: TypeScript tells me that "Argument of type 'RefOject' is not assignable to parater of type 'Element'.

Now, I don't know if what I'm trying to do is even possible, but if it is, could you guys help me a little? Maybe I'm missing something with ref (some conversion, I guess, but I really don't know what to do).

Thanks!

1

1 Answers

3
votes

You must first make sure that your ref has been created, which it is when the component is first mounted. The ref prop is used internally by React much like the key prop, so you must name it something else and treat it like any other prop.

Example

class Legend extends React.Component {
  render() {
    if (this.props.useRef) {
      return ReactDOM.createPortal(
        <div className="legend">Something</div>,
        this.props.portalRef
      );
    }
    return <div className="legend">Something else</div>;
  }
}

class Chart extends React.Component {
  myref = null;
  state = { mounted: false };

  componentDidMount() {
    // The ref has been created when the component has mounted.
    this.setState({ mounted: true });
  }

  render() {
    return (
      <div>
        <div className="container" ref={r => this.myref = r}>
          First Container
        </div>
        {this.state.mounted && <Legend portalRef={this.myref} useRef />}
      </div>
    );
  }
}

ReactDOM.render(<Chart />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"><div>