In react applications, we always have a root ponent and everything else is a child of that ponent.
So what I decided to do is break that convention whenever I am going to display a modal, and create a new element or a new ponent and append it directly to document.body
.
a child of body
we will not have anymore stacking z-index issues, so this modal will always show up 100% of the time. Or at least that was my thinking.
So I made a new ponent called modal.js
Inside of this modal, rather than returning a div with some fancy css styling on its children I am just going to return a no script tag which means don’t render anything like so:
import React, { Component } from 'react';
import ReactDOM from ‘react-dom’;
class Modal extends Component {
render() {
return <noscript />;
}
}
export default Modal;
So when I display the modal ponent its not going to display anything on the screen whatsoever. So then how do I get this modal on the screen then?
Well, I decided to do a bit of a workaround by adding in a ponentDidMount()
like so:
import React, { Component } from 'react';
import ReactDOM from ‘react-don’;
class Modal extends Component {
ponentDidMount() {
}
render() {
return <noscript />;
}
}
export default Modal;
So whenever this ponent gets mounted or rendered to the screen I am going to create a new div in memory and assign it to this.modalTarget
like so:
import React, { Component } from 'react'; import ReactDOM from ‘react-don’;
class Modal extends Component {
ponentDidMount() {
this.modalTarget = document.createElement(‘<div>’);
}
render() {
return <noscript />;
}
}
export default Modal;
Here is the finished file:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Modal extends Component {
ponentDidMount() {
this.modalTarget = document.createElement('<div>');
this.modalTarget.className = 'modal';
document.body.appendChild(this.modalTarget);
this._render();
}
ponentWillUpdate() {
this._render();
}
ponentWillUnmount() {
ReactDOM.unmountComponentAtNode(this.modalTarget);
document.body.removeChild(this.modalTarget);
}
_render() {
ReactDOM.render(<div>{this.props.children}</div>, this.modalTarget);
}
render() {
return <noscript />;
}
}
export default Modal;
I was expecting for this to work, maybe get an Inviolant error, but certain not:
Uncaught DOMException: Failed to execute 'createElement' on 'Document': The tag name provided
('<div>')
is not a valid name.
I am not sure what is going on here.
In react applications, we always have a root ponent and everything else is a child of that ponent.
So what I decided to do is break that convention whenever I am going to display a modal, and create a new element or a new ponent and append it directly to document.body
.
a child of body
we will not have anymore stacking z-index issues, so this modal will always show up 100% of the time. Or at least that was my thinking.
So I made a new ponent called modal.js
Inside of this modal, rather than returning a div with some fancy css styling on its children I am just going to return a no script tag which means don’t render anything like so:
import React, { Component } from 'react';
import ReactDOM from ‘react-dom’;
class Modal extends Component {
render() {
return <noscript />;
}
}
export default Modal;
So when I display the modal ponent its not going to display anything on the screen whatsoever. So then how do I get this modal on the screen then?
Well, I decided to do a bit of a workaround by adding in a ponentDidMount()
like so:
import React, { Component } from 'react';
import ReactDOM from ‘react-don’;
class Modal extends Component {
ponentDidMount() {
}
render() {
return <noscript />;
}
}
export default Modal;
So whenever this ponent gets mounted or rendered to the screen I am going to create a new div in memory and assign it to this.modalTarget
like so:
import React, { Component } from 'react'; import ReactDOM from ‘react-don’;
class Modal extends Component {
ponentDidMount() {
this.modalTarget = document.createElement(‘<div>’);
}
render() {
return <noscript />;
}
}
export default Modal;
Here is the finished file:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Modal extends Component {
ponentDidMount() {
this.modalTarget = document.createElement('<div>');
this.modalTarget.className = 'modal';
document.body.appendChild(this.modalTarget);
this._render();
}
ponentWillUpdate() {
this._render();
}
ponentWillUnmount() {
ReactDOM.unmountComponentAtNode(this.modalTarget);
document.body.removeChild(this.modalTarget);
}
_render() {
ReactDOM.render(<div>{this.props.children}</div>, this.modalTarget);
}
render() {
return <noscript />;
}
}
export default Modal;
I was expecting for this to work, maybe get an Inviolant error, but certain not:
Uncaught DOMException: Failed to execute 'createElement' on 'Document': The tag name provided
('<div>')
is not a valid name.
I am not sure what is going on here.
Share Improve this question asked Oct 30, 2018 at 22:53 DanielDaniel 15.5k19 gold badges112 silver badges181 bronze badges 2-
2
change
document.createElement(‘<div>’)
=>document.createElement("div")
- note the lack of<>
– Bravo Commented Oct 30, 2018 at 23:02 - @Bravo, that worked. Please post your answer. Thank you. – Daniel Commented Oct 30, 2018 at 23:09
2 Answers
Reset to default 4A ment from Bravo helped me solve this. What helped me was refactoring this:
this.modalTarget = document.createElement('<div>');
to this:
this.modalTarget = document.createElement('div');
Why don't you use the React.Fragment
?
You could do something like that...
const Modal = () => (
<React.Fragment>
<noscript />
</React.Fragment>
);
export default Modal;