Skip to content

Commit 8b141e4

Browse files
committed
fix(refUpdates): Adds defensive check to 'unobserve' method
On updates (re-rendering) there are cases where the ref callback gets called twice: first to nullify the DOM node and again when setting the new DOM node. ReactDOM.createPortal() for example causes this when it's re-rendered, causing an exception when we call unobserve() on a null node. Future updates should change the way we handle refs to a more solid solution.
1 parent 2bbec6c commit 8b141e4

File tree

2 files changed

+19
-1
lines changed

2 files changed

+19
-1
lines changed

src/IntersectionObserver.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,9 @@ export default class IntersectionObserver extends React.Component {
135135
}
136136

137137
unobserve() {
138-
IntersectionObserverContainer.unobserve(this);
138+
if (this.target != null) {
139+
IntersectionObserverContainer.unobserve(this);
140+
}
139141
}
140142

141143
reobserve() {

src/__tests__/IntersectionObserver.spec.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,22 @@ describe('update', () => {
236236
});
237237
expect(instance.shouldResetObserver).toBeTruthy();
238238
});
239+
240+
test('should be defensive against unobserving nullified nodes', () => {
241+
const spy = jest.spyOn(IntersectionObserverContainer, 'unobserve');
242+
const component = (
243+
<IntersectionObserver onChange={noop}>
244+
<span />
245+
</IntersectionObserver>
246+
);
247+
const tree = renderer.create(component, {
248+
createNodeMock: () => target,
249+
});
250+
tree.getInstance().target = null;
251+
tree.getInstance().unobserve();
252+
253+
expect(spy).not.toBeCalled();
254+
});
239255
});
240256

241257
describe('callback', () => {

0 commit comments

Comments
 (0)