Reduce workspace rerenders during explorer resize

This commit is contained in:
Mohamed Boudra
2026-04-22 22:18:11 +07:00
parent b133285f6d
commit 1f8f8e4036
3 changed files with 81 additions and 3 deletions
@@ -0,0 +1,56 @@
// @vitest-environment jsdom
import { act, renderHook } from "@testing-library/react";
import type { LayoutChangeEvent } from "react-native";
import { describe, expect, it } from "vitest";
import { useContainerWidthBelow } from "./use-container-width";
function layoutEvent(width: number): LayoutChangeEvent {
return {
nativeEvent: {
layout: {
width,
height: 48,
x: 0,
y: 0,
},
},
} as LayoutChangeEvent;
}
describe("useContainerWidthBelow", () => {
it("does not re-render for width changes that stay in the same threshold bucket", () => {
let renderCount = 0;
const { result } = renderHook(() => {
renderCount += 1;
return useContainerWidthBelow(700);
});
expect(result.current.isBelow).toBe(true);
expect(renderCount).toBe(1);
act(() => {
result.current.onLayout(layoutEvent(650));
result.current.onLayout(layoutEvent(620));
result.current.onLayout(layoutEvent(699));
});
expect(result.current.isBelow).toBe(true);
expect(renderCount).toBe(1);
});
it("re-renders when the width crosses the threshold", () => {
let renderCount = 0;
const { result } = renderHook(() => {
renderCount += 1;
return useContainerWidthBelow(700);
});
act(() => {
result.current.onLayout(layoutEvent(760));
});
expect(result.current.isBelow).toBe(false);
expect(renderCount).toBe(2);
});
});
@@ -16,3 +16,25 @@ export function useContainerWidth(): {
width, width,
}; };
} }
/**
* Tracks only whether a container is narrower than a threshold.
*/
export function useContainerWidthBelow(threshold: number): {
onLayout: (e: LayoutChangeEvent) => void;
isBelow: boolean;
} {
const [isBelow, setIsBelow] = useState(true);
return {
onLayout: useCallback(
(e: LayoutChangeEvent) => {
const nextIsBelow = e.nativeEvent.layout.width < threshold;
setIsBelow((currentIsBelow) =>
currentIsBelow === nextIsBelow ? currentIsBelow : nextIsBelow,
);
},
[threshold],
),
isBelow,
};
}
@@ -122,7 +122,7 @@ import { findAdjacentPane } from "@/utils/split-navigation";
import { isAbsolutePath } from "@/utils/path"; import { isAbsolutePath } from "@/utils/path";
import { useIsCompactFormFactor, supportsDesktopPaneSplits } from "@/constants/layout"; import { useIsCompactFormFactor, supportsDesktopPaneSplits } from "@/constants/layout";
import { isWeb, isNative } from "@/constants/platform"; import { isWeb, isNative } from "@/constants/platform";
import { useContainerWidth } from "@/hooks/use-container-width"; import { useContainerWidthBelow } from "@/hooks/use-container-width";
const TERMINALS_QUERY_STALE_TIME = 5_000; const TERMINALS_QUERY_STALE_TIME = 5_000;
const WORKSPACE_SETUP_AUTO_OPEN_WINDOW_MS = 30_000; const WORKSPACE_SETUP_AUTO_OPEN_WINDOW_MS = 30_000;
@@ -1051,8 +1051,8 @@ function WorkspaceScreenContent({
); );
const pendingByDraftId = useCreateFlowStore((state) => state.pendingByDraftId); const pendingByDraftId = useCreateFlowStore((state) => state.pendingByDraftId);
const { closingTabIds, closeTab } = useCloseTabs(); const { closingTabIds, closeTab } = useCloseTabs();
const { onLayout: onHeaderLayout, width: headerWidth } = useContainerWidth(); const { onLayout: onHeaderLayout, isBelow: showCompactButtonLabels } =
const showCompactButtonLabels = headerWidth < 700; useContainerWidthBelow(700);
const closeWorkspaceTabWithCleanup = useCallback( const closeWorkspaceTabWithCleanup = useCallback(
function closeWorkspaceTabWithCleanup(input: { function closeWorkspaceTabWithCleanup(input: {
tabId: string; tabId: string;