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`] = `