Skip to content

Commit c0b29a8

Browse files
committed
fix(layout): Added fixes required for Concurrent Rendering
1 parent 5946bd9 commit c0b29a8

File tree

6 files changed

+41
-32
lines changed

6 files changed

+41
-32
lines changed

packages/layout/src/LayoutProvider.tsx

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import {
22
createContext,
3+
ReactElement,
34
ReactNode,
45
useCallback,
56
useContext,
7+
useEffect,
68
useMemo,
79
useState,
8-
useRef,
9-
ReactElement,
1010
} from "react";
1111
import { useAppSize } from "@react-md/utils";
1212

@@ -166,22 +166,18 @@ export function LayoutProvider({
166166
largeDesktopLayout,
167167
].some((layout) => !!layout && isMiniLayout(layout));
168168

169-
const isPersistent = isPersistentLayout(layout);
170-
171169
const { isDesktop } = appSize;
172170
const [visible, setVisible] = useState(
173-
(isPersistent && isDesktop) ||
171+
(isPersistentLayout(layout) && isDesktop) ||
174172
isToggleableVisible(defaultToggleableVisible, layout)
175173
);
176-
const prevLayout = useRef(layout);
177-
if (prevLayout.current !== layout) {
178-
prevLayout.current = layout;
179-
const nextVisible =
180-
isPersistent || isToggleableVisible(defaultToggleableVisible, layout);
181-
if (visible !== nextVisible) {
182-
setVisible(nextVisible);
183-
}
184-
}
174+
175+
useEffect(() => {
176+
setVisible(
177+
isPersistentLayout(layout) ||
178+
isToggleableVisible(defaultToggleableVisible, layout)
179+
);
180+
}, [defaultToggleableVisible, layout]);
185181

186182
const showNav = useCallback(() => {
187183
setVisible(true);

packages/layout/src/__tests__/Layout.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
getByText as getByTextGlobal,
1616
render as baseRender,
1717
waitForElementToBeRemoved,
18+
waitFor,
1819
} from "@testing-library/react";
1920
import {
2021
HomeSVGIcon,
@@ -630,7 +631,7 @@ describe("Layout", () => {
630631
});
631632
});
632633

633-
it("should maintain state while switching between static and mini layouts", () => {
634+
it("should maintain state while switching between static and mini layouts", async () => {
634635
const navItems: LayoutNavigationTree = {
635636
"/": {
636637
href: "/",
@@ -685,7 +686,9 @@ describe("Layout", () => {
685686
expect(checkbox).toBeChecked();
686687

687688
fireEvent.click(getByRole("button", { name: "Mobile" }));
688-
expect(getNav).toThrow();
689+
await waitFor(() => {
690+
expect(getNav).toThrow();
691+
});
689692
expect(getMiniNav).not.toThrow();
690693
expect(checkbox).toBeInTheDocument();
691694
expect(checkbox).toBeChecked();

packages/layout/src/useLayoutNavigation.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ElementType, useRef } from "react";
1+
import { ElementType, useEffect } from "react";
22
import { Link } from "@react-md/link";
33
import {
44
BaseTreeItem,
@@ -100,15 +100,23 @@ export function useLayoutNavigation<
100100
const { expandedIds, onItemExpansion, onMultiItemExpansion } =
101101
useTreeItemExpansion(() => getParentIds(itemId, navItems));
102102

103-
const prevItemId = useRef(itemId);
104-
const prevNavItems = useRef(navItems);
105-
if (prevItemId.current !== itemId || prevNavItems.current !== navItems) {
106-
prevItemId.current = itemId;
107-
prevNavItems.current = navItems;
108-
onMultiItemExpansion(
109-
Array.from(new Set([...expandedIds, ...getParentIds(itemId, navItems)]))
110-
);
111-
}
103+
useEffect(() => {
104+
onMultiItemExpansion((prevExpandedIds) => {
105+
const nextExpandedIds = [
106+
...new Set([...prevExpandedIds, ...getParentIds(itemId, navItems)]),
107+
];
108+
if (nextExpandedIds.length !== prevExpandedIds.length) {
109+
return nextExpandedIds;
110+
}
111+
112+
const prevSorted = prevExpandedIds.slice().sort();
113+
const nextSorted = nextExpandedIds.slice().sort();
114+
115+
return nextSorted.some((itemId, index) => itemId !== prevSorted[index])
116+
? nextSorted
117+
: prevSorted;
118+
});
119+
}, [itemId, navItems, onMultiItemExpansion]);
112120

113121
return {
114122
navItems,

packages/tree/src/types.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import type {
22
CSSProperties,
3+
Dispatch,
34
ElementType,
45
HTMLAttributes,
56
MutableRefObject,
67
ReactElement,
78
ReactNode,
89
Ref,
10+
SetStateAction,
911
} from "react";
1012
import type {
1113
ListItemChildrenProps,
@@ -146,8 +148,11 @@ export interface TreeItemExpansion {
146148
/**
147149
* A function to call when the user presses the asterisk key (*) that will
148150
* expand all tree items at the same level as the currently focused item.
151+
*
152+
* @remarks \@since 4.0.1 Allows for callback behavior to get current
153+
* `expandedIds`.
149154
*/
150-
onMultiItemExpansion(itemIds: ExpandedIds): void;
155+
onMultiItemExpansion: Dispatch<SetStateAction<ExpandedIds>>;
151156
}
152157

153158
export interface TreeItemSelection {

packages/tree/src/useTreeItemExpansion.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,9 @@ export function useTreeItemExpansion(
3636
[]
3737
);
3838

39-
const onMultiItemExpansion = useCallback((itemIds: ExpandedIds) => {
40-
setExpandedIds(itemIds);
41-
}, []);
42-
4339
return {
4440
expandedIds,
4541
onItemExpansion,
46-
onMultiItemExpansion,
42+
onMultiItemExpansion: setExpandedIds,
4743
};
4844
}

tsconfig.base.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"esModuleInterop": true,
1111
"moduleResolution": "node",
1212
"resolveJsonModule": true,
13+
"downlevelIteration": true,
1314
"noFallthroughCasesInSwitch": true,
1415
"allowSyntheticDefaultImports": true,
1516
"forceConsistentCasingInFileNames": true,

0 commit comments

Comments
 (0)