简体   繁体   中英

React and using ReactDOM.createPortal() - Target container is not a DOM element Error

I'm working on a React app and am trying to use ReactDOM.createPortal() to add html content to a div that is outside the component (called ToDoItem).

{ReactDOM.createPortal(
    <Route path={`/profile/project/${this.props.project._id}`} render={() => 
    <ProjectView project={this.props.project}/>}  />,
    document.getElementById('tasks')
)}

None of the HTML in the public folder is predefined - it is all dynamically created.

I think this could be the cause of the error: React tries to add HTML to the div with the id of tasks which, but the div is not loaded into the DOM before this happens?

If this method is incorrect, is there any other method I can use append html content to another div outside the component?

Some other info: the component from which I tried to run this method is a stateless component, not a class component.

This is the error:

在此处输入图像描述

Before first render of components, there is no element in the DOM and document.getElementById cannot reach to any element. elements added to DOM after first render.

Use useRef in parent component and send it to Portal Component .

In parent component:

const tasksRef = React.useRef(null);
const [tasksSt, setTasksSt]= React.useState();

....
    <div  ref={
        (current) => {tasksRef.current = current;
                setTasksSt(tasksRef.current);
                }
            }/>
    <YourPortalComp tasksRef={tasksRef} /> 
              

In Portal Component

{this.props.tasksRef.current?(ReactDom.createPortal(<...>, this.props.tasksRef.current):null}

You can wait until the DOM is ready using React.useEffect , and then you call ReactDOM.createPortal :

function Component() { 
  const [domReady, setDomReady] = React.useState(false)

  React.useEffect(() => {
    setDomReady(true)
  })

  return domReady 
    ? ReactDOM.createPortal(<div>Your Component</div>, document.getElementById('container-id')) 
    : null
}

If the target element (In your case element with id tasks ) is loaded but still you are getting the Target container is not a DOM element Error error, you can try the below solution.

 const MyElement = () => { const [containerToLoad, setContainerToLoad] = useState(null); // If the target element is ready and loaded // set the target element useEffect(() => { setContainerToLoad(document.getElementById('container')); }, []); return containerToLoad && createPortal(<div>modal content</div>, containerToLoad); };

The problem is that you can't createProtal to react component. the second parameter have to be dom elemenet, not react created element

I had this issue because I forgot to add <div id="some-id"></div> to my index.html file :-D

So just as a reminder for anyone who has a similar problem or doesn't know how to use React portals ( to create a modal for example):

in modal.jsx :

const modalRoot = document.getElementById('modal');

const Modal = () => {
  const modalElement = document.createElement('div');

  // appends the modal to portal once modal's children are mounted and 
  // removes it once we don't need it in the DOM anymore:
  useEffect(() => {
    modalRoot.appendChild(modalElement);
    return () => {
      modalRoot.removeChild(modalElement);
    };
  }, [modalElement]);

  return createPortal(<div>modal content</div>, modalRoot);
};

in index.html :

<!DOCTYPE html>
<html lang="en">
  <head>
    // head content
  </head>
  <body>
    <div id="root"></div>
    // dont't forget about this:
    <div id="modal"></div>
  </body>
</html>

check your id in index.html file, So lets say, your index.html file has: <div id="overlays"></div>

Your Modal should point to same div, ie

const portalElement = document.getElementById('overlays');
const Modal = (props) => {
return (
    <Fragment>
      {ReactDOM.createPortal(<Backdrop onClose={props.onClose} />, portalElement)}
  </Fragment>
 );

};

For those that might be using Next.js, an equivalent to AlexxBoro's answer for next.js can be found here. https://www.learnbestcoding.com/post/101/how-to-create-a-portal-in-next.js

First parameter of createPortal should be a dom element. You are not passing a dom element (you are passing an instance of Route).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM