fix(hooks): useSessionState reset honours the current default, not a frozen one
Also found uncommitted in the shared tree; unrelated to agent panels, so it lands on its own. `reset` closed over `initialValue` from the first render, and its `useCallback` dep list deliberately omitted it — with an eslint-disable to silence the warning that was correctly pointing at the bug. Any caller whose default is computed (derived from props, from a fetch, from another piece of state) got reset to whatever that default happened to be on mount, which after the first render is the wrong value. Reads through a ref instead, so reset always sees the current default. The eslint-disable goes away because there is nothing left to suppress — the dep list is honest now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -76,6 +76,8 @@ export function useSessionState<T>(key: string, initialValue: T) {
|
|||||||
valueRef.current = value;
|
valueRef.current = value;
|
||||||
const setGlobalRef = useRef(setGlobal);
|
const setGlobalRef = useRef(setGlobal);
|
||||||
setGlobalRef.current = setGlobal;
|
setGlobalRef.current = setGlobal;
|
||||||
|
const initialValueRef = useRef(initialValue);
|
||||||
|
initialValueRef.current = initialValue;
|
||||||
|
|
||||||
const setValue = useCallback(
|
const setValue = useCallback(
|
||||||
(arg: React.SetStateAction<T>) => {
|
(arg: React.SetStateAction<T>) => {
|
||||||
@@ -86,11 +88,11 @@ export function useSessionState<T>(key: string, initialValue: T) {
|
|||||||
[key],
|
[key],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Read through the ref, not the closure: resetting means "whatever the default is now", and a
|
||||||
|
// `useCallback` over `initialValue` would freeze the default from the render that built the callback.
|
||||||
const reset = useCallback(() => {
|
const reset = useCallback(() => {
|
||||||
clearSessionValue(key);
|
clearSessionValue(key);
|
||||||
setGlobalRef.current(initialValue);
|
setGlobalRef.current(initialValueRef.current);
|
||||||
// `initialValue` is read at reset time on purpose: resetting means "whatever the default is now".
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [key]);
|
}, [key]);
|
||||||
|
|
||||||
return [value, setValue, reset] as const;
|
return [value, setValue, reset] as const;
|
||||||
|
|||||||
Reference in New Issue
Block a user