Skip to content

Commit 25600d4

Browse files
TheSharpieOneeddywashere
authored andcommitted
fix(TetherContent): rerender when other props change (#128)
Fix #125 Let the TetherContent rerender when any props change while it is showing. This allows the children to update dynamically without needing to hide and show the content to force the update.
1 parent 8fd0761 commit 25600d4

2 files changed

Lines changed: 82 additions & 8 deletions

File tree

src/TetherContent.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ class TetherContent extends React.Component {
3232
componentDidUpdate(prevProps) {
3333
if (this.props.isOpen !== prevProps.isOpen) {
3434
this.handleProps();
35+
} else if (this._element) {
36+
// rerender
37+
this.renderIntoSubtree();
3538
}
3639
}
3740

@@ -94,11 +97,7 @@ class TetherContent extends React.Component {
9497

9598
this._element = document.createElement('div');
9699
document.body.appendChild(this._element);
97-
ReactDOM.unstable_renderSubtreeIntoContainer(
98-
this,
99-
this.renderChildren(),
100-
this._element
101-
);
100+
this.renderIntoSubtree();
102101

103102
if (this.props.arrow) {
104103
const arrow = document.createElement('div');
@@ -119,6 +118,14 @@ class TetherContent extends React.Component {
119118
return this.props.toggle();
120119
}
121120

121+
renderIntoSubtree() {
122+
ReactDOM.unstable_renderSubtreeIntoContainer(
123+
this,
124+
this.renderChildren(),
125+
this._element
126+
);
127+
}
128+
122129
renderChildren() {
123130
const { children, style } = this.props;
124131
return React.cloneElement(

test/TetherContent.spec.js

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,14 @@ describe('TetherContent', () => {
8181
});
8282

8383
describe('show', () => {
84-
it('should be called on componentWillUnmount', () => {
84+
it('should be called on componentDidMount', () => {
8585
state = true;
86-
spyOn(TetherContent.prototype, 'componentWillUnmount').and.callThrough();
86+
spyOn(TetherContent.prototype, 'componentDidMount').and.callThrough();
8787
spyOn(TetherContent.prototype, 'show').and.callThrough();
8888
const wrapper = mount(<TetherContent tether={tetherConfig} isOpen={state} toggle={toggle}><p>Content</p></TetherContent>);
8989
const instance = wrapper.instance();
9090

91-
expect(TetherContent.prototype.componentWillUnmount.calls.count()).toBe(0);
91+
expect(TetherContent.prototype.componentDidMount.calls.count()).toBe(1);
9292
expect(TetherContent.prototype.show.calls.count()).toBe(1);
9393
expect(instance._element.textContent).toBe('Content');
9494
expect(instance._tether.enabled).toBe(true);
@@ -234,4 +234,71 @@ describe('TetherContent', () => {
234234
expect(instance.props.isOpen).toBe(false);
235235
});
236236
});
237+
238+
describe('renderIntoSubtree', () => {
239+
it('should be called when the content is shown', () => {
240+
spyOn(TetherContent.prototype, 'renderIntoSubtree').and.callThrough();
241+
mount(<TetherContent tether={tetherConfig} isOpen toggle={toggle}><p>Content</p></TetherContent>);
242+
243+
expect(TetherContent.prototype.renderIntoSubtree.calls.count()).toBe(1);
244+
});
245+
246+
it('should be called when the content is not shown', () => {
247+
spyOn(TetherContent.prototype, 'renderIntoSubtree').and.callThrough();
248+
mount(<TetherContent tether={tetherConfig} isOpen={false} toggle={toggle}><p>Content</p></TetherContent>);
249+
250+
expect(TetherContent.prototype.renderIntoSubtree.calls.count()).toBe(0);
251+
});
252+
253+
it('should be called on componentDidUpdate when isOpen did not change is true', () => {
254+
spyOn(TetherContent.prototype, 'componentDidUpdate').and.callThrough();
255+
spyOn(TetherContent.prototype, 'renderIntoSubtree').and.callThrough();
256+
const wrapper = mount(<TetherContent tether={tetherConfig} isOpen toggle={toggle}><p>Content</p></TetherContent>);
257+
const instance = wrapper.instance();
258+
259+
expect(TetherContent.prototype.componentDidUpdate.calls.count()).toBe(0);
260+
expect(TetherContent.prototype.renderIntoSubtree.calls.count()).toBe(1);
261+
expect(instance.props.isOpen).toBe(true);
262+
263+
wrapper.setProps({ children: <span>something</span> });
264+
265+
expect(TetherContent.prototype.componentDidUpdate.calls.count()).toBe(1);
266+
expect(TetherContent.prototype.renderIntoSubtree.calls.count()).toBe(2);
267+
expect(instance.props.isOpen).toBe(true);
268+
});
269+
270+
it('should not be called on componentDidUpdate when isOpen changed to false', () => {
271+
spyOn(TetherContent.prototype, 'componentDidUpdate').and.callThrough();
272+
spyOn(TetherContent.prototype, 'renderIntoSubtree').and.callThrough();
273+
const wrapper = mount(<TetherContent tether={tetherConfig} isOpen toggle={toggle}><p>Content</p></TetherContent>);
274+
const instance = wrapper.instance();
275+
276+
expect(TetherContent.prototype.componentDidUpdate.calls.count()).toBe(0);
277+
expect(TetherContent.prototype.renderIntoSubtree.calls.count()).toBe(1);
278+
expect(instance.props.isOpen).toBe(true);
279+
280+
wrapper.setProps({ isOpen: false });
281+
282+
expect(TetherContent.prototype.componentDidUpdate.calls.count()).toBe(1);
283+
expect(TetherContent.prototype.renderIntoSubtree.calls.count()).toBe(1);
284+
expect(instance.props.isOpen).toBe(false);
285+
});
286+
287+
it('should not be called on componentDidUpdate when isOpen did not change and is false', () => {
288+
spyOn(TetherContent.prototype, 'componentDidUpdate').and.callThrough();
289+
spyOn(TetherContent.prototype, 'renderIntoSubtree').and.callThrough();
290+
const wrapper = mount(<TetherContent tether={tetherConfig} isOpen={false} toggle={toggle}><p>Content</p></TetherContent>);
291+
const instance = wrapper.instance();
292+
293+
expect(TetherContent.prototype.componentDidUpdate.calls.count()).toBe(0);
294+
expect(TetherContent.prototype.renderIntoSubtree.calls.count()).toBe(0);
295+
expect(instance.props.isOpen).toBe(false);
296+
297+
wrapper.setProps({ children: <span>something</span> });
298+
299+
expect(TetherContent.prototype.componentDidUpdate.calls.count()).toBe(1);
300+
expect(TetherContent.prototype.renderIntoSubtree.calls.count()).toBe(0);
301+
expect(instance.props.isOpen).toBe(false);
302+
});
303+
});
237304
});

0 commit comments

Comments
 (0)