Skip to content

Commit 3a15b7f

Browse files
committed
fix(ViewportProvider): only notify if requested properties change
1 parent 4deec23 commit 3a15b7f

File tree

4 files changed

+74
-17
lines changed

4 files changed

+74
-17
lines changed

examples/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class Example extends React.PureComponent<{}, { disabled: boolean }> {
7272
<ObserveViewport
7373
disableDimensionsUpdates
7474
onUpdate={props => {
75-
console.log('update scroll', props.scroll);
75+
console.log('update scroll only', props.scroll);
7676
}}
7777
/>
7878
<ObserveViewport

lib/ObserveViewport.tsx

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
IDimensions,
1212
IViewport,
1313
TViewportChangeHandler,
14+
IViewportChangeOptions,
1415
} from './types';
1516

1617
export interface IChildProps {
@@ -28,16 +29,28 @@ interface IProps {
2829
}
2930

3031
interface IContext {
31-
addViewportChangeListener: (fn: TViewportChangeHandler) => void;
32-
removeViewportChangeListener: (fn: TViewportChangeHandler) => void;
32+
addViewportChangeListener: (
33+
handler: TViewportChangeHandler,
34+
options: IViewportChangeOptions,
35+
) => void;
36+
removeViewportChangeListener: (
37+
handler: TViewportChangeHandler,
38+
options: IViewportChangeOptions,
39+
) => void;
3340
}
3441

3542
export default class ObserveViewport extends React.Component<IProps, IState> {
3643
private addViewportChangeListener:
37-
| ((fn: TViewportChangeHandler) => void)
44+
| ((
45+
handler: TViewportChangeHandler,
46+
options: IViewportChangeOptions,
47+
) => void)
3848
| null;
3949
private removeViewportChangeListener:
40-
| ((fn: TViewportChangeHandler) => void)
50+
| ((
51+
handler: TViewportChangeHandler,
52+
options: IViewportChangeOptions,
53+
) => void)
4154
| null;
4255

4356
private tickId: NodeJS.Timer;
@@ -61,7 +74,10 @@ export default class ObserveViewport extends React.Component<IProps, IState> {
6174

6275
componentWillUnmount() {
6376
if (this.removeViewportChangeListener) {
64-
this.removeViewportChangeListener(this.handleViewportUpdate);
77+
this.removeViewportChangeListener(this.handleViewportUpdate, {
78+
notifyScroll: !this.props.disableScrollUpdates,
79+
notifyDimensions: !this.props.disableDimensionsUpdates,
80+
});
6581
}
6682
this.removeViewportChangeListener = null;
6783
this.addViewportChangeListener = null;
@@ -100,10 +116,16 @@ export default class ObserveViewport extends React.Component<IProps, IState> {
100116
}
101117

102118
if (this.removeViewportChangeListener) {
103-
this.removeViewportChangeListener(this.handleViewportUpdate);
119+
this.removeViewportChangeListener(this.handleViewportUpdate, {
120+
notifyScroll: !this.props.disableScrollUpdates,
121+
notifyDimensions: !this.props.disableDimensionsUpdates,
122+
});
104123
}
105124
this.removeViewportChangeListener = removeViewportChangeListener;
106-
addViewportChangeListener(this.handleViewportUpdate);
125+
addViewportChangeListener(this.handleViewportUpdate, {
126+
notifyScroll: !this.props.disableScrollUpdates,
127+
notifyDimensions: !this.props.disableDimensionsUpdates,
128+
});
107129
return null;
108130
};
109131

lib/ViewportProvider.tsx

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,27 @@ import {
1616
IPrivateScroll,
1717
IScroll,
1818
TViewportChangeHandler,
19+
IViewportChangeOptions,
1920
} from './types';
2021

22+
interface IListener extends IViewportChangeOptions {
23+
handler: TViewportChangeHandler;
24+
}
25+
2126
export const SCROLL_DIR_DOWN = Symbol('SCROLL_DIR_DOWN');
2227
export const SCROLL_DIR_UP = Symbol('SCROLL_DIR_UP');
2328
export const SCROLL_DIR_LEFT = Symbol('SCROLL_DIR_LEFT');
2429
export const SCROLL_DIR_RIGHT = Symbol('SCROLL_DIR_RIGHT');
2530

2631
const ViewportContext = React.createContext({
27-
removeViewportChangeListener: (props: TViewportChangeHandler) => {},
28-
addViewportChangeListener: (props: TViewportChangeHandler) => {},
32+
removeViewportChangeListener: (
33+
handler: TViewportChangeHandler,
34+
options: IViewportChangeOptions,
35+
) => {},
36+
addViewportChangeListener: (
37+
handler: TViewportChangeHandler,
38+
options: IViewportChangeOptions,
39+
) => {},
2940
});
3041

3142
const getNodeScroll = (elem = window) => {
@@ -121,7 +132,7 @@ export default class ViewportProvider extends React.PureComponent {
121132
private lastSyncedScrollState: IPrivateScroll;
122133
private lastSyncedDimensionsState: IDimensions;
123134
private tickId: NodeJS.Timer;
124-
private listeners: TViewportChangeHandler[] = [];
135+
private listeners: IListener[] = [];
125136

126137
constructor(props: {}) {
127138
super(props);
@@ -222,8 +233,13 @@ export default class ViewportProvider extends React.PureComponent {
222233

223234
if (scrollDidUpdate || dimensionsDidUpdate) {
224235
const publicState = this.getPropsFromState();
225-
this.listeners.forEach(listener => {
226-
listener(publicState);
236+
this.listeners.forEach(({ handler, notifyScroll, notifyDimensions }) => {
237+
if (
238+
(notifyScroll && scrollDidUpdate) ||
239+
(notifyDimensions && dimensionsDidUpdate)
240+
) {
241+
handler(publicState);
242+
}
227243
});
228244
}
229245
};
@@ -239,12 +255,26 @@ export default class ViewportProvider extends React.PureComponent {
239255
};
240256
}
241257

242-
addViewportChangeListener = (fn: TViewportChangeHandler) => {
243-
this.listeners.push(fn);
258+
addViewportChangeListener = (
259+
handler: TViewportChangeHandler,
260+
options: IViewportChangeOptions,
261+
) => {
262+
this.listeners.push({ handler, ...options });
244263
};
245264

246-
removeViewportChangeListener = (fn: TViewportChangeHandler) => {
247-
this.listeners = this.listeners.filter(listener => listener !== fn);
265+
removeViewportChangeListener = (
266+
h: TViewportChangeHandler,
267+
options: IViewportChangeOptions,
268+
) => {
269+
this.listeners = this.listeners.filter(
270+
({ handler, notifyScroll, notifyDimensions }) => {
271+
const equals =
272+
handler === h &&
273+
notifyScroll === options.notifyScroll &&
274+
notifyDimensions === options.notifyDimensions;
275+
return !equals;
276+
},
277+
);
248278
};
249279

250280
render() {

lib/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,8 @@ export interface IViewport {
4949
}
5050

5151
export type TViewportChangeHandler = ({ scroll, dimensions }: IViewport) => void;
52+
53+
export interface IViewportChangeOptions {
54+
notifyScroll: boolean;
55+
notifyDimensions: boolean;
56+
}

0 commit comments

Comments
 (0)