prop-types icon indicating copy to clipboard operation
prop-types copied to clipboard

React Portals can't be validated with prop-types

Open betalb opened this issue 6 years ago • 4 comments

PropTypes.node is not accepting element, created by React.createPortal as valid

Is it possible to treat element created by React.createPortal as iterator over it's children or treat portal itself as valid node?

betalb avatar Mar 01 '18 11:03 betalb

Any update on this?

I'm experiencing the same issue.

The React type definitions state that ReactPortal is a valid ReactNode, but it seems prop-types disagrees at runtime.

React version: 16.3.1

Steps To Reproduce

  1. Create new React app with CRA
  2. Implement simple routing setup using BrowserRouter from react-router-dom
  3. Call ReactDOM.createPortal(React.createElement(Link, { to: "/other-page" }, "OTHER PAGE"), mountPoint) as a direct child of BrowserRouter (see code sample below)
  4. Run app, see console for warning
Code sample:
import React, { useState, useRef, useEffect } from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import logo from "./logo.svg";
import "./App.css";

function App() {
  const [mountPoint, setMountPoint] = useState();

  const mountRef = useRef(null);

  useEffect(() => {
    if (mountRef.current) {
      setMountPoint(mountRef.current);
    }
  }, [setMountPoint, mountRef]);

  return (
    <>
      <div ref={mountRef} id="test-id"></div>
      <Router>
        {mountPoint
          ? ReactDOM.createPortal(
              React.createElement(Link, { to: "/other-page" }, "OTHER PAGE"),
              mountPoint
            )
          : null}
        <Switch>
          <Route path="/" exact>
            <div className="App">
              <header className="App-header">
                <img src={logo} className="App-logo" alt="logo" />
                <p>
                  Edit <code>src/App.js</code> and save to reload.
                </p>
                <a
                  className="App-link"
                  href="https://reactjs.org"
                  target="_blank"
                  rel="noopener noreferrer"
                >
                  Learn React
                </a>
              </header>
            </div>
          </Route>
          <Route path="/other-page">
            <Link to="/">HOME</Link>
            <h1>Other page</h1>
          </Route>
        </Switch>
      </Router>
    </>
  );
}

export default App;

Link to code example:

Edit hnipps/portal-prop-type

The current behavior

The app renders and behaves as expected but this console error is thrown:

Warning: Failed prop type: Invalid prop `children` supplied to `BrowserRouter`, expected a ReactNode.

The expected behavior

No error thrown because ReactPortal is a valid ReactNode.

hnipps avatar Aug 11 '20 00:08 hnipps

any workaround to suppress this warning? this is quite annoying as this warning is false positive

Eliav2 avatar May 29 '22 12:05 Eliav2

Any news on this one please ?

Ysandor avatar Jul 20 '22 21:07 Ysandor

In my case it helped to simply wrap createPortal in a fragment, i.e. instead of

<div>
  <div>bla</div>
  {createPortal(<div>Hello, World!</div>, targetEl)}
</div>

do

<div>
  <div>bla</div>
  <>
    {createPortal(<div>Hello, World!</div>, targetEl)}
  </>
</div>

Console error is gone, now.

donalffons avatar Aug 18 '22 21:08 donalffons