1

I did a function that creates a modal programatically for React 17, where you just needed to call a function to create a new modal.

It was working fantastic before the ReactDOM.render was deprecated.

Is there a way to replace the render function with something else in React 18? Right now the createRoot function is only for the root component, I want to render simple components in a specified DOM element.

It worked like this:

app.jsx

<button onClick={() => createModal(<h1>I'm a component inside a modal</h1>)}>Open Modal</button>

It handles it's own state, very useful if you want to make a bunch of modals in seconds.

This is the code:

index.js => Here is the container.

import React from 'react'
import ReactDOM from 'react-dom'
import './index.scss'
import App from './App.jsx'

ReactDOM.render(
  <React.StrictMode>
    <div id="modal-container"></div> <- This is the container
    <App />
  </React.StrictMode>,
  document.getElementById('root')
)

Modal/Modal.jsx => The modal component.

import { useState } from 'react'
import './Modal.scss'

const Modal = ({ content }) => {
    const [isOpen, setIsOpen] = useState(true)

    if (isOpen) {
        return (<>
            <div className="modal-background" onClick={() => setIsOpen(false)} />

            <div className="modal-content" >
                {content}
            </div>

            <button onClick={() => setIsOpen(false)} className="close-button" >Close</button>
        </>)
    } else return null
}

export default Modal

Modal/index.js => The call function:

import { render } from "react-dom"
import Modal from "./Modal"

const createModal = (content) => render(
    <Modal key={Math.random()} content={content} />, document.getElementById("modal-container")
)

export default createModal
  • 2
    Have you tried with the "Portal" concept in react? Seems very similar to what you are trying to accomplish. https://reactjs.org/docs/portals.html – Dehn Hunsworth Jul 25 '22 at 19:07
  • 1
    In your case you should move this `` above `root` div in `\public\index.html` page – Abhishek Singh Jul 25 '22 at 19:20
  • Thanks for your responses! Unfortunately, it doesn't worked, no matter how I did it, createPortal never renders anything when using it with a function. :( – DoRyu Dracken Jul 25 '22 at 23:04

1 Answers1

1

It worked using createRoot this way, instead of render:

Here is an example: CodeSandbox

Modal/index.js

import { createRoot } from 'react-dom/client'
import Modal from "./Modal"

const createModal = (content) => {
    if (!window.modalContainer) {
        window.modalContainer = createRoot(document.getElementById('modal-container'))
    }

    window.modalContainer.render(<Modal key={Math.random()} content={content} />)
}
export default createModal

It checks if createRoot on the specified component has been called before, so it only call createRoot once, and the render function any time a new modal is created.

If you have a better answer it would be awesome too. :)

  • what is modalContainer ?I have a similar question, this is the question link https://stackoverflow.com/questions/73518170/react-18-warning-reactdomclient-createroot-on-a-container-that-has-already-be?noredirect=1#comment129826292_73518170 – zahra zamani Aug 29 '22 at 10:40
  • 1
    @zahrazamani It's a global variable containing a new "root"...... in HTML, the global scope is the window object, i.e. `window.modalContainer = "Any value you want"`...... The reason is; You're going to render a modal several times, but you can't call [createRoot] more than once...... So you create a new "root" only once, and store it as a global variable `window.modalContainer`, so you can use it every time you want without calling "createRoot" every time. – DoRyu Dracken Aug 29 '22 at 16:58
  • 1
    I tried with this method but I still get this Warning:You are calling ReactDOMClient.createRoot() on a container that has already been passed to createRoot() before. Instead, call root.render() on the existing root instead if you want to update it. – zahra zamani Aug 30 '22 at 04:00
  • 1
    @zahrazamani I made a [CodeSanbox](https://codesandbox.io/s/stupefied-banach-zfw77g?file=/src/App.js) for you with a working example and some extra options... I hope it helps... Everything is in the folder `"/components/modal"`, just remember to add the container `` in the index file. – DoRyu Dracken Aug 31 '22 at 20:15