Skip to content

Commit 376c4e6

Browse files
committed
[feature] deprecate getParentElement in favor of a local element.
This patch will give us the ability to place the modal in any place in the react tree. Each modal can handle its own clean up. Test case was written by @restrry [b9a3415](https://github.com/restrry/react-modal/commit/b9a34155bf37298e99922f77dec8e27292db06d9).
1 parent 6f73764 commit 376c4e6

File tree

4 files changed

+23
-65
lines changed

4 files changed

+23
-65
lines changed

README.md

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -148,24 +148,8 @@ object will apply to all instances of the modal.
148148

149149
### Appended to custom node
150150

151-
You can choose an element for the modal to be appended to, rather than using
152-
body tag. To do this, provide a function to `parentSelector` prop that return
153-
the element to be used.
154-
155-
```jsx
156-
157-
function getParent() {
158-
return document.querySelector('#root');
159-
}
160-
161-
<Modal
162-
...
163-
parentSelector={getParent}
164-
...
165-
>
166-
<p>Modal Content.</p>
167-
</Modal>
168-
```
151+
`parentSelector` is now deprecated. `<Modal />` can be appended on any place
152+
and it will correctly manage it's clean up.
169153

170154
### Body class
171155

docs/README.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,6 @@ import ReactModal from 'react-modal';
7878
String indicating the role of the modal, allowing the 'dialog' role to be applied if desired.
7979
*/
8080
role="dialog"
81-
/*
82-
Function that will be called to get the parent element that the modal will be attached to.
83-
*/
84-
parentSelector={() => document.body}
8581
/>
8682
```
8783

specs/Modal.spec.js

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -54,26 +54,24 @@ describe('State', () => {
5454
ReactDOM.unmountComponentAtNode(node);
5555
});
5656

57-
it('renders into the body, not in context', () => {
58-
const node = document.createElement('div');
57+
it('renders in context, never in document.body', function() {
58+
var node = document.createElement('div');
59+
var realRef = null;
5960
class App extends Component {
6061
render() {
61-
return (
62-
<div>
63-
<Modal isOpen>
64-
<span>hello</span>
65-
</Modal>
62+
return (
63+
<div ref={ref => { realRef = ref; }}>
64+
<Modal isOpen={true}>
65+
<span>hello</span>
66+
</Modal>
6667
</div>
67-
);
68+
);
6869
}
6970
}
7071
Modal.setAppElement(node);
7172
ReactDOM.render(<App />, node);
72-
expect(
73-
document.body.querySelector('.ReactModalPortal').parentNode
74-
).toEqual(
75-
document.body
76-
);
73+
var modalParent = node.querySelector('.ReactModalPortal').parentNode;
74+
expect(modalParent).toEqual(realRef);
7775
ReactDOM.unmountComponentAtNode(node);
7876
});
7977

src/components/Modal.js

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@ export const bodyOpenClassName = 'ReactModal__Body--open';
1010

1111
const renderSubtreeIntoContainer = ReactDOM.unstable_renderSubtreeIntoContainer;
1212

13-
function getParentElement(parentSelector) {
14-
return parentSelector();
15-
}
16-
1713
export default class Modal extends Component {
1814
static setAppElement(element) {
1915
ariaAppHider.setElement(element);
@@ -52,7 +48,6 @@ export default class Modal extends Component {
5248
closeTimeoutMS: PropTypes.number,
5349
ariaHideApp: PropTypes.bool,
5450
shouldCloseOnOverlayClick: PropTypes.bool,
55-
parentSelector: PropTypes.func,
5651
role: PropTypes.string,
5752
contentLabel: PropTypes.string.isRequired
5853
};
@@ -64,8 +59,7 @@ export default class Modal extends Component {
6459
bodyOpenClassName,
6560
ariaHideApp: true,
6661
closeTimeoutMS: 0,
67-
shouldCloseOnOverlayClick: true,
68-
parentSelector() { return document.body; }
62+
shouldCloseOnOverlayClick: true
6963
};
7064

7165
static defaultStyles = {
@@ -94,12 +88,6 @@ export default class Modal extends Component {
9488
};
9589

9690
componentDidMount() {
97-
this.node = document.createElement('div');
98-
this.node.className = this.props.portalClassName;
99-
100-
const parent = getParentElement(this.props.parentSelector);
101-
parent.appendChild(this.node);
102-
10391
this.renderPortal(this.props);
10492
}
10593

@@ -108,23 +96,9 @@ export default class Modal extends Component {
10896
// Stop unnecessary renders if modal is remaining closed
10997
if (!this.props.isOpen && !isOpen) return;
11098

111-
const currentParent = getParentElement(this.props.parentSelector);
112-
const newParent = getParentElement(newProps.parentSelector);
113-
114-
if (newParent !== currentParent) {
115-
currentParent.removeChild(this.node);
116-
newParent.appendChild(this.node);
117-
}
118-
11999
this.renderPortal(newProps);
120100
}
121101

122-
componentWillUpdate(newProps) {
123-
if (newProps.portalClassName !== this.props.portalClassName) {
124-
this.node.className = newProps.portalClassName;
125-
}
126-
}
127-
128102
componentWillUnmount() {
129103
if (!this.node) return;
130104

@@ -145,10 +119,12 @@ export default class Modal extends Component {
145119
}
146120
}
147121

122+
setNodeRef = ref => {
123+
this.node = ref;
124+
}
125+
148126
removePortal = () => {
149127
ReactDOM.unmountComponentAtNode(this.node);
150-
const parent = getParentElement(this.props.parentSelector);
151-
parent.removeChild(this.node);
152128
}
153129

154130
renderPortal = props => {
@@ -158,6 +134,10 @@ export default class Modal extends Component {
158134
}
159135

160136
render() {
161-
return null;
137+
return (
138+
<div
139+
ref={this.setNodeRef}
140+
className={this.props.portalClassName} />
141+
);
162142
}
163143
}

0 commit comments

Comments
 (0)