Skip to content

Commit e6d0fa5

Browse files
author
Luis Merino
committed
fix(sentinel): ensure sentinel re-observes after items render
The intersection observer will re-attach the target, to fix a case occurring when an itemLength update is too small and has the sentinel re-render within the intersecting area. This prevented the intersection event from happening either until the intersection changed again or alltogether when using `awaitMore` due to the `awaitIntersection` set fag.
1 parent 7fe392c commit e6d0fa5

File tree

4 files changed

+20
-10
lines changed

4 files changed

+20
-10
lines changed

docs/docs/components/AsyncList/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export default class extends React.Component {
6060
})
6161
.catch(err => {
6262
console.error(err); // eslint-disable-line
63+
this.feedList([]);
6364
});
6465
};
6566

src/Sentinel.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ export default class Sentinel extends React.PureComponent {
1515

1616
this.state = {
1717
rootElement: undefined,
18-
sentinel: <sentinel style={{ height: 1, display: 'block' }} />,
1918
rootMargin: this.computeRootMargin(props),
2019
};
2120

@@ -44,21 +43,26 @@ export default class Sentinel extends React.PureComponent {
4443
this.setState({
4544
rootMargin: this.computeRootMargin(nextProps),
4645
});
46+
} else {
47+
this.observer.reobserve();
4748
}
4849
}
4950

5051
render() {
5152
const { onChange } = this.props;
52-
const { rootElement, sentinel, rootMargin } = this.state;
53+
const { rootElement, rootMargin } = this.state;
5354

5455
return (
5556
<Observer
57+
ref={node => {
58+
this.observer = node;
59+
}}
5660
disabled={typeof rootElement === 'undefined'}
5761
root={rootElement}
5862
rootMargin={rootMargin}
5963
onChange={onChange}
6064
>
61-
{sentinel}
65+
<sentinel style={{ height: 1, display: 'block' }} />
6266
</Observer>
6367
);
6468
}

src/__tests__/List.spec.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,21 +147,21 @@ describe('handleUpdate', () => {
147147
).not.toThrow();
148148
});
149149

150-
test('sets next size value using `pageSize`', () => {
150+
test('sets next size value computed into `pageSize`', () => {
151151
const instance = createTree({ itemsLength: 20 }).getInstance();
152152
instance.handleUpdate({ isIntersecting: false });
153153
instance.handleUpdate({ isIntersecting: true });
154154
expect(instance.state.size).toBe(20);
155155
});
156156

157-
test('sets next size value using `itemsLength`', () => {
157+
test('sets next size value computed into `itemsLength`', () => {
158158
const instance = createTree({ itemsLength: 15 }).getInstance();
159159
instance.handleUpdate({ isIntersecting: false });
160160
instance.handleUpdate({ isIntersecting: true });
161161
expect(instance.state.size).toBe(15);
162162
});
163163

164-
test('calls `onIntersection` if size updates', () => {
164+
test('calls `onIntersection` each time when `awaitIntersection` is falsy', () => {
165165
const spy = jest.fn();
166166
const instance = createTree({
167167
itemsLength: 30,
@@ -174,7 +174,7 @@ describe('handleUpdate', () => {
174174
expect(spy).toHaveBeenCalledTimes(2);
175175
});
176176

177-
test('calls `onIntersection` only once with `awaitMore` until size updates', () => {
177+
test('calls `onIntersection` only once when `awaitIntersection` is true', () => {
178178
const spy = jest.fn();
179179
const tree = createTree({
180180
awaitMore: true,

src/__tests__/Sentinel.spec.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ describe('constructor', () => {
4343
});
4444

4545
describe('render', () => {
46-
test('provides a disabled observer', () => {
46+
test('first time sets a disabled observer', () => {
4747
const spy = require('@researchgate/react-intersection-observer');
4848
createTree();
4949
expect(spy.mock.calls[spy.mock.calls.length - 1][0]).toHaveProperty('disabled', true);
@@ -62,20 +62,25 @@ describe('render', () => {
6262
test('avoids re-render if new props are the same', () => {
6363
const tree = createTree();
6464
const renderSpy = jest.spyOn(tree.getInstance(), 'render');
65+
const spy = jest.fn();
66+
tree.getInstance().observer = {
67+
reobserve: spy,
68+
};
6569
tree.update(<Sentinel {...defaultProps} />);
6670
expect(renderSpy).not.toBeCalled();
71+
expect(spy).toBeCalled();
6772
});
6873
});
6974

7075
describe('compute', () => {
71-
test('returns valid computeRootMargin', () => {
76+
test('returns computed rootMargin', () => {
7277
const instance = createTree().getInstance();
7378
expect(instance.computeRootMargin({ threshold: '50%', axis: 'x' })).toBe('0% 50%');
7479
expect(instance.computeRootMargin({ threshold: '50px', axis: 'y' })).toBe('50px 0px');
7580
expect(instance.computeRootMargin({ threshold: '50', axis: 'y' })).toBe('50 0');
7681
});
7782

78-
test('executed receiving new axis or threshold prop', () => {
83+
test('new axis or threshold props set new rootMargin', () => {
7984
const instance = createTree().getInstance();
8085
instance.componentWillReceiveProps({ ...defaultProps, axis: 'x' });
8186
expect(instance.state.rootMargin).toBe('0px 100px');

0 commit comments

Comments
 (0)