perf: Improve performance of rendering context menus

This commit is contained in:
Tom Moor
2023-09-04 23:29:19 -04:00
parent 5f788012db
commit 262590e507
5 changed files with 145 additions and 107 deletions

View File

@@ -1,28 +0,0 @@
import * as React from "react";
export default function useDebouncedCallback<T>(
callback: (...params: T[]) => unknown,
wait: number
) {
// track args & timeout handle between calls
const argsRef = React.useRef<T[]>();
const timeout = React.useRef<ReturnType<typeof setTimeout>>();
function cleanup() {
if (timeout.current) {
clearTimeout(timeout.current);
}
}
// make sure our timeout gets cleared if consuming component gets unmounted
React.useEffect(() => cleanup, []);
return function (...args: T[]) {
argsRef.current = args;
cleanup();
timeout.current = setTimeout(() => {
if (argsRef.current) {
callback(...argsRef.current);
}
}, wait);
};
}

View File

@@ -0,0 +1,40 @@
import throttle from "lodash/throttle";
import * as React from "react";
import useUnmount from "./useUnmount";
interface ThrottleSettings {
leading?: boolean | undefined;
trailing?: boolean | undefined;
}
const defaultOptions: ThrottleSettings = {
leading: false,
trailing: true,
};
/**
* A hook that returns a throttled callback function.
*
* @param fn The function to throttle
* @param wait The time in ms to wait before calling the function
* @param dependencies The dependencies to watch for changes
* @param options The throttle options
*/
export default function useThrottledCallback<T extends (...args: any[]) => any>(
fn: T,
wait = 250,
dependencies: React.DependencyList = [],
options: ThrottleSettings = defaultOptions
) {
const handler = React.useMemo(
() => throttle<T>(fn, wait, options),
// eslint-disable-next-line react-hooks/exhaustive-deps
dependencies
);
useUnmount(() => {
handler.cancel();
});
return handler;
}

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import useDebouncedCallback from "./useDebouncedCallback";
import useEventListener from "./useEventListener";
import useThrottledCallback from "./useThrottledCallback";
/**
* A debounced hook that listens to the window resize event and returns the
@@ -14,22 +14,25 @@ export default function useWindowSize() {
height: window.innerHeight,
});
const handleResize = useDebouncedCallback(() => {
if (
window.innerWidth !== windowSize.width ||
window.innerHeight !== windowSize.height
) {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
const handleResize = useThrottledCallback(() => {
setWindowSize((state) => {
if (
window.innerWidth === state.width &&
window.innerHeight === state.height
) {
return state;
}
return { width: window.innerWidth, height: window.innerHeight };
});
}, 100);
useEventListener("resize", handleResize);
// Call handler right away so state gets updated with initial window size
handleResize();
React.useEffect(() => {
handleResize();
}, [handleResize]);
return windowSize;
}