feat: add memoization

This commit is contained in:
Arnošt Pleskot 2023-09-13 15:57:50 +02:00
parent dd9bde5ee7
commit b4e80b602d
No known key found for this signature in database

View file

@ -1,4 +1,5 @@
import { AppState, ScrollConstraints } from "../types"; import { AppState, ScrollConstraints } from "../types";
import { isShallowEqual } from "../utils";
import { getNormalizedZoom } from "./zoom"; import { getNormalizedZoom } from "./zoom";
/** /**
@ -301,6 +302,15 @@ const isViewportOutsideOfConstrainedArea = (state: AppState) => {
); );
}; };
let memoizedValues: {
previousState: Pick<
AppState,
"zoom" | "width" | "height" | "scrollConstraints"
>;
constraints: ReturnType<typeof calculateConstraints>;
constraintsWithoutOverscroll: ReturnType<typeof calculateConstraints>;
} | null = null;
/** /**
* Constrains the AppState scroll values within the defined scroll constraints. * Constrains the AppState scroll values within the defined scroll constraints.
* *
@ -323,47 +333,75 @@ export const constrainScrollState = (
} }
const { scrollX, scrollY, width, height, scrollConstraints, zoom } = state; const { scrollX, scrollY, width, height, scrollConstraints, zoom } = state;
const constrainedValues = constrainScrollValues({ const canUseMemoizedValues =
...calculateConstraints({ memoizedValues?.previousState.scrollConstraints && // can't use memoized values if there were no scrollConstraints in memoizedValues
memoizedValues && // there are memoized values
isShallowEqual(
// current scrollConstraints are the same as in memoizedValues
state.scrollConstraints,
memoizedValues.previousState.scrollConstraints!,
) &&
isShallowEqual(
// current zoom and window dimensions are equal to those in memoizedValues
{ zoom: zoom.value, width, height },
{
zoom: memoizedValues.previousState.zoom.value,
width: memoizedValues.previousState.width,
height: memoizedValues.previousState.height,
},
);
const constraints = canUseMemoizedValues
? memoizedValues!.constraints
: calculateConstraints({
scrollConstraints, scrollConstraints,
width, width,
height, height,
zoom, zoom,
cursorButton: "down", cursorButton: "down",
}),
scrollX,
scrollY,
}); });
const shouldAnimate = isViewportOutsideOfConstrainedArea(state); const constraintsWithoutOverscroll = canUseMemoizedValues
? memoizedValues!.constraintsWithoutOverscroll
const animateTo = shouldAnimate : calculateConstraints({
? constrainScrollValues({
...calculateConstraints({
scrollConstraints, scrollConstraints,
width, width,
height, height,
zoom, zoom,
cursorButton: "up", cursorButton: "up",
}), });
const constrainedValues = constrainScrollValues({
...constraints,
scrollX, scrollX,
scrollY, scrollY,
}) });
: null;
const animateTo = constrainScrollValues({
...constraintsWithoutOverscroll,
scrollX,
scrollY,
});
if (!canUseMemoizedValues) {
memoizedValues = {
previousState: {
zoom: state.zoom,
width: state.width,
height: state.height,
scrollConstraints: state.scrollConstraints,
},
constraints,
constraintsWithoutOverscroll,
};
}
if (
constrainedValues.scrollX !== scrollX ||
constrainedValues.scrollY !== scrollY
) {
return { return {
state: { state: {
...state, ...state,
...constrainedValues, ...constrainedValues,
}, },
shouldAnimate, shouldAnimate: isViewportOutsideOfConstrainedArea(state),
animateTo, animateTo,
}; };
}
return { state, shouldAnimate, animateTo };
}; };