From 1de69e316d0a4afdbeaa3c5d043ed01289fe5eb5 Mon Sep 17 00:00:00 2001 From: John Babak Date: Mon, 13 Jun 2016 15:47:26 +0300 Subject: [PATCH] Update `className` and `style` when new props arrive Fixes https://github.com/tajo/react-portal/issues/72 --- lib/portal.js | 30 +++++++++++++++++++----------- test/portal_spec.js | 14 +++++++++++++- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/lib/portal.js b/lib/portal.js index 452309c..2eeb818 100644 --- a/lib/portal.js +++ b/lib/portal.js @@ -126,21 +126,29 @@ export default class Portal extends React.Component { } } + applyClassNameAndStyle(props) { + if (props.className) { + this.node.className = props.className; + } + if (props.style) { + // React 15.1.0+ requires third parameter in debug mode + /* eslint-disable no-underscore-dangle */ + CSSPropertyOperations.setValueForStyles(this.node, + props.style, + this._reactInternalInstance); + /* eslint-enable no-underscore-dangle */ + } + } + renderPortal(props) { if (!this.node) { this.node = document.createElement('div'); - if (props.className) { - this.node.className = props.className; - } - if (props.style) { - // React 15.1.0+ requires third parameter in debug mode - /* eslint-disable no-underscore-dangle */ - CSSPropertyOperations.setValueForStyles(this.node, - props.style, - this._reactInternalInstance); - /* eslint-enable no-underscore-dangle */ - } + // apply CSS before the node is added to the DOM to avoid needless reflows + this.applyClassNameAndStyle(props); document.body.appendChild(this.node); + } else { + // update CSS when new props arrive + this.applyClassNameAndStyle(props); } this.portal = ReactDOM.unstable_renderSubtreeIntoContainer( this, diff --git a/test/portal_spec.js b/test/portal_spec.js index 73881c2..d634eca 100644 --- a/test/portal_spec.js +++ b/test/portal_spec.js @@ -77,11 +77,23 @@ describe('react-portal', () => { assert.equal(document.body.lastElementChild.className, 'some-class'); }); - it('should add inline style to portal\'s wrapping node', () => { + it('should add inline style to the portal\'s wrapping node', () => { mount(

Hi

); assert.equal(document.body.lastElementChild.style.color, 'blue'); }); + it('should update className on the portal\'s wrapping node when props.className changes', () => { + const wrapper = mount(

Hi

); + wrapper.setProps({ className: 'some-other-class', children:

Hi

}); + assert.equal(document.body.lastElementChild.className, 'some-other-class'); + }); + + it('should update inline style on the portal\'s wrapping node when props.style changes', () => { + const wrapper = mount(

Hi

); + wrapper.setProps({ style: { color: 'red' }, children:

Hi

}); + assert.equal(document.body.lastElementChild.style.color, 'red'); + }); + describe('callbacks', () => { it('should call props.beforeClose() if passed when calling Portal.closePortal()', () => { const props = { isOpened: true, beforeClose: spy() };