From 987893aa676f43f7b286dbd580056e90eb64adb5 Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Tue, 4 Feb 2025 15:06:09 +0100 Subject: [PATCH] Fix loop in secondary navigation render cycle --- .../secondary_navigation_context.yaml | 2 + scm-ui/ui-api/src/localStorage.ts | 31 +++++++++++----- .../src/__snapshots__/storyshots.test.ts.snap | 15 ++++++-- .../src/layout/SecondaryNavigationColumn.tsx | 11 +++++- .../src/navigation/ExternalNavLink.tsx | 6 +-- .../ui-components/src/navigation/NavLink.tsx | 16 +++----- .../SecondaryNavigation.stories.tsx | 11 ++++-- .../src/navigation/SecondaryNavigation.tsx | 15 ++------ .../navigation/SecondaryNavigationContext.ts | 19 ---------- .../navigation/SecondaryNavigationContext.tsx | 37 +++++++++++++++++++ .../src/useSecondaryNavigation.tsx | 28 ++++++-------- .../base/forms/chip-input/ChipInputField.tsx | 1 - scm-ui/ui-extensions/src/extensionPoints.tsx | 2 +- .../roles/containers/SingleRepositoryRole.tsx | 2 +- 14 files changed, 112 insertions(+), 84 deletions(-) create mode 100644 gradle/changelog/secondary_navigation_context.yaml delete mode 100644 scm-ui/ui-components/src/navigation/SecondaryNavigationContext.ts create mode 100644 scm-ui/ui-components/src/navigation/SecondaryNavigationContext.tsx diff --git a/gradle/changelog/secondary_navigation_context.yaml b/gradle/changelog/secondary_navigation_context.yaml new file mode 100644 index 0000000000..8816fb76c7 --- /dev/null +++ b/gradle/changelog/secondary_navigation_context.yaml @@ -0,0 +1,2 @@ +- type: fixed + description: Loop in secondary navigation render cycle diff --git a/scm-ui/ui-api/src/localStorage.ts b/scm-ui/ui-api/src/localStorage.ts index 42c48d7c5d..24b1a57066 100644 --- a/scm-ui/ui-api/src/localStorage.ts +++ b/scm-ui/ui-api/src/localStorage.ts @@ -37,7 +37,7 @@ const determineInitialValue = (key: string, initialValue: T) => { */ export function useLocalStorage(key: string, initialValue: T): [value: T, setValue: LocalStorageSetter] { const initialValueOrValueFromStorage = useMemo(() => determineInitialValue(key, initialValue), [key, initialValue]); - const [item, setItem] = useState(initialValueOrValueFromStorage); + const [item, setItem] = useState(initialValueOrValueFromStorage); useEffect(() => { const listener = (event: StorageEvent) => { @@ -50,14 +50,27 @@ export function useLocalStorage(key: string, initialValue: T): [value: T, set }, [key, initialValue]); const setValue: LocalStorageSetter = (newValue) => { - const computedNewValue = newValue instanceof Function ? newValue(item) : newValue; - setItem(computedNewValue); - const json = JSON.stringify(computedNewValue); - localStorage.setItem(key, json); - // storage event is no triggered in same tab - window.dispatchEvent( - new StorageEvent("storage", { key, oldValue: item, newValue: json, storageArea: localStorage }) - ); + // We've got to use setItem here to get the actual current value for item, not the one we got when this function was + // created, in other words: We want to get rid of the dependency to item to get a similar behaviour as the setter + // from useState. + // (We also could wrap this function in a useCallback, but then we'd had to put this function in a dependency array + // when we use this function so that we always refer to the current function. This is not the case for useState.) + setItem((oldValue) => { + const computedNewValue = newValue instanceof Function ? newValue(oldValue) : newValue; + setItem(computedNewValue); + const json = JSON.stringify(computedNewValue); + localStorage.setItem(key, json); + // storage event is not triggered in same tab + window.dispatchEvent( + new StorageEvent("storage", { + key, + oldValue: JSON.stringify(oldValue), + newValue: json, + storageArea: localStorage, + }) + ); + return computedNewValue; + }); }; return [item, setValue]; diff --git a/scm-ui/ui-components/src/__snapshots__/storyshots.test.ts.snap b/scm-ui/ui-components/src/__snapshots__/storyshots.test.ts.snap index aed5f205e5..a74f7cb029 100644 --- a/scm-ui/ui-components/src/__snapshots__/storyshots.test.ts.snap +++ b/scm-ui/ui-components/src/__snapshots__/storyshots.test.ts.snap @@ -78158,11 +78158,18 @@ exports[`Storyshots Secondary Navigation Active when match 1`] = `