Issue
I am using portal in React and want to get access to elements from other components.
For example, I have components with:
// here I want to put some content via portal
<div id='buttons'></div>
That is my component where I create portal
const elem = document.getElementById('buttons');
return (
<div className="block-mainContent">
{isLoading ?
<Loader />
:
<Table
data={memoCustomers}
headers={headers}
actionRender={actionRender}
showCheckbox
onSelect={onSelect}
onSelectAll={onSelectAll}
selectedRows={Array.from(selectedIds)}
/>}
<Modal
isOpen={isOpen}
onClose={() => dispatch(closeModalAction())}
content={editModalContent()}
/>
{!!elem && createPortal(<button>test</button>, elem)} // !!! here is my portal !!!
</div>
);
My problem is I get such error "Target container is not a DOM element
As I understand, the problem happens because I try to get an element before it is mounted and as result I get null.
How to check if my div elemen exists and then to create portal?
I try to use different approaches. In the code above I use that
{!!elem && createPortal(<button>test</button>, elem)}
// here I check If element exists it will return true and portal will be created
// but it works a bit wrong. Describe it below
It helps to remove error, but my portal starts working only at the second render. I mean, after loading my page there is no portal. If only I make smth on the page, rerender happens and portal appears.
I tried else
const [mounted, setMounted] = useState(false)
useEffect(() => {
setMounted(true)
}, []);
{mounted && createPortal(<button>test</button>, elem)}
// here I create portal in the first render via useEffect and
But it throws the same error. No one of my ideas works.
If you know how to fix it, thank you in advance!
Solution
I think you need to create your buttons element to the parent component which of you need to create portal, or html body in index.html
.
For example
// index.html in public folder if
<html>
<body>
<div id="root"></div>
<div id='buttons'></div>
</body>
...
</html>
or in your parent component without using useRef and follow your previous coding style
import React, { useEffect, useState } from "react";
import { createPortal } from "react-dom";
const PortalContainer = () => {
return <div id={"buttons"}></div>;
};
const Home = () => {
const [mounted, setMounted] = useState(false);
const [portalElement, setPortalElement] = useState();
useEffect(() => {
setMounted(true);
}, []);
useEffect(() => {
const portalContainer = document.getElementById("buttons");
if (portalContainer)
setPortalElement(createPortal(<button>test</button>, portalContainer));
}, [mounted]);
return (
<>
<h2>Portal Testing</h2>
<PortalContainer />
{portalElement}
</>
);
};
export default Home;
Answered By - ClusterH
Answer Checked By - - Marie Seifert (ReactFix Admin)