Skip to content

Commit d43f5ef

Browse files
committed
feat(React16.4): Migrated codebase to stop using legacy lifecycles
1 parent bbc208b commit d43f5ef

File tree

2 files changed

+87
-76
lines changed

2 files changed

+87
-76
lines changed

src/IntersectionObserver.js

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -117,17 +117,23 @@ export default class IntersectionObserver extends React.Component {
117117
}
118118
};
119119

120-
handleNode = node => {
120+
handleNode = target => {
121121
if (typeof this.props.children.ref === 'function') {
122-
this.props.children.ref(node);
122+
this.props.children.ref(target);
123123
}
124-
if (this.currentTarget && node && this.currentTarget !== node) {
124+
if (this.renderedTarget && target && this.renderedTarget !== target) {
125125
this.unobserve();
126-
this.shouldResetObserver = true;
126+
this.targetChanged = true;
127127
}
128-
this.target = node;
128+
this.target = target;
129129
};
130130

131+
compareObserverProps(prevProps) {
132+
return observerOptions
133+
.concat(['disabled'])
134+
.some(option => shallowCompareOptions(this.props[option], prevProps[option]));
135+
}
136+
131137
observe() {
132138
this.target = isDOMTypeElement(this.target) ? this.target : findDOMNode(this.target);
133139
this.observer = IntersectionObserverContainer.create(callback, this.options);
@@ -160,24 +166,18 @@ export default class IntersectionObserver extends React.Component {
160166
}
161167
}
162168

163-
componentWillUnmount() {
164-
this.unobserve();
165-
}
166-
167-
componentDidUpdate() {
168-
if (this.shouldResetObserver) {
169+
componentDidUpdate(prevProps) {
170+
if (this.targetChanged || this.compareObserverProps(prevProps)) {
169171
this.reobserve();
170172
}
171173
}
172174

173-
componentWillUpdate(nextProps) {
174-
this.shouldResetObserver = observerOptions
175-
.concat(['disabled'])
176-
.some(option => shallowCompareOptions(nextProps[option], this.props[option]));
175+
componentWillUnmount() {
176+
this.unobserve();
177177
}
178178

179179
render() {
180-
this.currentTarget = this.target;
180+
this.renderedTarget = this.target; // this value is null on the first render
181181

182182
return React.cloneElement(React.Children.only(this.props.children), {
183183
ref: this.handleNode,

src/__tests__/IntersectionObserver.spec.js

Lines changed: 71 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ test("should remove target from the observer targets' list on umount", () => {
114114
});
115115

116116
describe('update', () => {
117-
test('componentWillUpdate determines whether the observer should restart', () => {
117+
test('componentDidUpdate reobserves the target with observer prop changes', () => {
118118
const component = (
119119
<IntersectionObserver onChange={noop}>
120120
<span />
@@ -141,7 +141,7 @@ describe('update', () => {
141141
);
142142
let called = false;
143143
const tree = renderer.create(component, {
144-
createNodeMock: () => {
144+
createNodeMock() {
145145
if (called) {
146146
return target;
147147
}
@@ -160,7 +160,7 @@ describe('update', () => {
160160
);
161161

162162
tree.update(
163-
<IntersectionObserver onChange={noop} rootMargin="1%">
163+
<IntersectionObserver onChange={noop}>
164164
<div />
165165
</IntersectionObserver>,
166166
);
@@ -171,70 +171,81 @@ describe('update', () => {
171171
});
172172

173173
test('should reobserve with new root, rootMargin and/or threshold props', () => {
174-
const winElement = Object.assign({ id: 'window' }, target);
175-
const docElement = Object.assign({ id: 'document' }, target);
174+
const root1 = Object.assign({ id: 'window' }, target);
175+
const root2 = Object.assign({ id: 'document' }, target);
176176
const initialProps = {
177177
onChange: noop,
178-
root: winElement,
178+
root: root1,
179179
rootMargin: '10% 20%',
180180
threshold: 0.5,
181181
};
182-
const children = <span />;
183-
const component = <IntersectionObserver {...initialProps}>{children}</IntersectionObserver>;
184-
const instance = renderer.create(component, { createNodeMock: () => target }).getInstance();
185-
const nextProps = { ...initialProps, children };
186-
187-
instance.componentWillUpdate(nextProps);
188-
expect(instance.shouldResetObserver).toBeFalsy();
189-
190-
instance.componentWillUpdate({
191-
...nextProps,
192-
children: <div />,
193-
});
194-
expect(instance.shouldResetObserver).toBeFalsy();
195-
196-
instance.componentWillUpdate({
197-
...nextProps,
198-
root: docElement,
199-
});
200-
expect(instance.shouldResetObserver).toBeTruthy();
201-
202-
instance.componentWillUpdate({
203-
...nextProps,
204-
root: winElement,
205-
});
206-
expect(instance.shouldResetObserver).toBeFalsy();
207-
208-
instance.componentWillUpdate({
209-
...nextProps,
210-
root: winElement,
211-
rootMargin: '20% 10%',
212-
});
213-
expect(instance.shouldResetObserver).toBeTruthy();
214-
215-
instance.componentWillUpdate({
216-
...nextProps,
217-
rootMargin: '20% 10%',
218-
});
219-
expect(instance.shouldResetObserver).toBeTruthy();
220-
221-
instance.componentWillUpdate({
222-
...nextProps,
223-
threshold: [0.5, 1],
224-
});
225-
expect(instance.shouldResetObserver).toBeTruthy();
182+
const component = (
183+
<IntersectionObserver {...initialProps}>
184+
<span />
185+
</IntersectionObserver>
186+
);
187+
const tree = renderer.create(component, { createNodeMock: () => target });
188+
const instance = tree.getInstance();
189+
const spy1 = jest.spyOn(instance, 'unobserve');
190+
const spy2 = jest.spyOn(instance, 'observe');
226191

227-
instance.componentWillUpdate({
228-
...nextProps,
229-
threshold: [0, 0.25, 0.5, 0.75, 1],
230-
});
231-
expect(instance.shouldResetObserver).toBeTruthy();
192+
// none of the props updating
193+
tree.update(
194+
<IntersectionObserver {...initialProps}>
195+
<span />
196+
</IntersectionObserver>,
197+
);
198+
// only children updating
199+
tree.update(
200+
<IntersectionObserver {...initialProps}>
201+
<div />
202+
</IntersectionObserver>,
203+
);
204+
// only root updating (document)
205+
tree.update(
206+
<IntersectionObserver {...initialProps} root={root2}>
207+
<div />
208+
</IntersectionObserver>,
209+
);
210+
// only root updating (window)
211+
tree.update(
212+
<IntersectionObserver {...initialProps} root={root1}>
213+
<div />
214+
</IntersectionObserver>,
215+
);
216+
// only rootMargin updating
217+
tree.update(
218+
<IntersectionObserver {...initialProps} root={root1} rootMargin="20% 10%">
219+
<div />
220+
</IntersectionObserver>,
221+
);
222+
// only root updating (null)
223+
tree.update(
224+
<IntersectionObserver {...initialProps} rootMargin="20% 10%">
225+
<div />
226+
</IntersectionObserver>,
227+
);
228+
// only threshold updating (non-scalar)
229+
tree.update(
230+
<IntersectionObserver {...initialProps} threshold={[0.5, 1]}>
231+
<div />
232+
</IntersectionObserver>,
233+
);
234+
// only threshold updating (length changed)
235+
tree.update(
236+
<IntersectionObserver {...initialProps} threshold={[0, 0.25, 0.5, 0.75, 1]}>
237+
<div />
238+
</IntersectionObserver>,
239+
);
240+
// only threshold updating (scalar)
241+
tree.update(
242+
<IntersectionObserver {...initialProps} threshold={1}>
243+
<div />
244+
</IntersectionObserver>,
245+
);
232246

233-
instance.componentWillUpdate({
234-
...nextProps,
235-
threshold: 1,
236-
});
237-
expect(instance.shouldResetObserver).toBeTruthy();
247+
expect(spy1).toHaveBeenCalledTimes(6);
248+
expect(spy2).toHaveBeenCalledTimes(6);
238249
});
239250

240251
test('should be defensive against unobserving nullified nodes', () => {

0 commit comments

Comments
 (0)