Skip to content

Commit

Permalink
feat(ObserveViewport): trigger updates after prop change via schedule…
Browse files Browse the repository at this point in the history
…r to reduce layout trashing
  • Loading branch information
garthenweb committed Oct 20, 2019
1 parent dd3cd1c commit 035e4e2
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 12 deletions.
25 changes: 13 additions & 12 deletions lib/ObserveViewport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,20 @@ interface IContext {
options: IViewportChangeOptions,
) => void;
removeViewportChangeListener: (handler: TViewportChangeHandler) => void;
scheduleReinitializeChangeHandler: (handler: TViewportChangeHandler) => void;
hasRootProviderAsParent: boolean;
getCurrentViewport: () => IViewport;
version: string;
}

export default class ObserveViewport extends React.Component<IProps, IState> {
private getCurrentViewport?: () => IViewport;
private removeViewportChangeListener?:
| ((handler: TViewportChangeHandler) => void)
| null;
private removeViewportChangeListener?: (
handler: TViewportChangeHandler,
) => void;
private scheduleReinitializeChangeHandler?: (
handler: TViewportChangeHandler,
) => void;

private tickId: number;

Expand All @@ -77,24 +81,19 @@ export default class ObserveViewport extends React.Component<IProps, IState> {
const scrollBecameActive =
!this.props.disableScrollUpdates && prevProps.disableScrollUpdates;
if (
typeof this.getCurrentViewport === 'function' &&
typeof this.scheduleReinitializeChangeHandler === 'function' &&
(dimensionsBecameActive || scrollBecameActive)
) {
const viewport = this.getCurrentViewport();
this.handleViewportUpdate(
viewport,
this.props.recalculateLayoutBeforeUpdate
? this.props.recalculateLayoutBeforeUpdate(viewport)
: null,
);
this.scheduleReinitializeChangeHandler(this.handleViewportUpdate);
}
}

componentWillUnmount() {
if (this.removeViewportChangeListener) {
this.removeViewportChangeListener(this.handleViewportUpdate);
}
this.removeViewportChangeListener = null;
this.removeViewportChangeListener = undefined;
this.scheduleReinitializeChangeHandler = undefined;
cancelAnimationFrame(this.tickId);
}

Expand Down Expand Up @@ -126,6 +125,7 @@ export default class ObserveViewport extends React.Component<IProps, IState> {
registerViewportListeners = ({
addViewportChangeListener,
removeViewportChangeListener,
scheduleReinitializeChangeHandler,
hasRootProviderAsParent,
getCurrentViewport,
}: IContext): React.ReactNode => {
Expand All @@ -147,6 +147,7 @@ export default class ObserveViewport extends React.Component<IProps, IState> {

this.removeViewportChangeListener = removeViewportChangeListener;
this.getCurrentViewport = getCurrentViewport;
this.scheduleReinitializeChangeHandler = scheduleReinitializeChangeHandler;
addViewportChangeListener(this.handleViewportUpdate, {
notifyScroll: () => !this.props.disableScrollUpdates,
notifyDimensions: () => !this.props.disableDimensionsUpdates,
Expand Down
10 changes: 10 additions & 0 deletions lib/ViewportProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const createFallbackViewportRequester = () => {

export const ViewportContext = React.createContext({
removeViewportChangeListener: (handler: TViewportChangeHandler) => {},
scheduleReinitializeChangeHandler: (handler: TViewportChangeHandler) => {},
addViewportChangeListener: (
handler: TViewportChangeHandler,
options: IViewportChangeOptions,
Expand Down Expand Up @@ -219,6 +220,14 @@ export default class ViewportProvider extends React.PureComponent<
this.handleListenerUpdate();
};

scheduleReinitializeChangeHandler = (h: TViewportChangeHandler) => {
const listener = this.listeners.find(({ handler }) => handler === h);
if (listener && listener.initialized) {
listener.initialized = false;
this.handleListenerUpdate();
}
};

removeViewportChangeListener = (h: TViewportChangeHandler) => {
this.listeners = this.listeners.filter(({ handler }) => handler !== h);
this.handleListenerUpdate();
Expand Down Expand Up @@ -261,6 +270,7 @@ export default class ViewportProvider extends React.PureComponent<
private contextValue = {
addViewportChangeListener: this.addViewportChangeListener,
removeViewportChangeListener: this.removeViewportChangeListener,
scheduleReinitializeChangeHandler: this.scheduleReinitializeChangeHandler,
getCurrentViewport: () => {
if (!this.collector.current) {
return this.getCurrentDefaultViewport();
Expand Down
1 change: 1 addition & 0 deletions lib/__tests__/ObserveViewport.client.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// force fallback to setTimeout
delete window.requestAnimationFrame;
delete window.cancelAnimationFrame;
jest.useFakeTimers();

import React from 'react';
Expand Down

0 comments on commit 035e4e2

Please sign in to comment.