From fdd1b23fd7ba6ae30139eeef02c552a8c7d6d333 Mon Sep 17 00:00:00 2001 From: Arnaud de Surirey Date: Wed, 14 Apr 2021 15:27:11 +0200 Subject: [PATCH] fix(useLocalStorage): reinitialize on key change --- src/useLocalStorage.ts | 10 ++++++++-- tests/useLocalStorage.test.ts | 13 +++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/useLocalStorage.ts b/src/useLocalStorage.ts index 2b77bfa6..def6ad80 100644 --- a/src/useLocalStorage.ts +++ b/src/useLocalStorage.ts @@ -1,4 +1,4 @@ -import { Dispatch, SetStateAction, useCallback, useState } from 'react'; +import { Dispatch, SetStateAction, useCallback, useState, useRef, useLayoutEffect } from 'react'; import { isBrowser, noop } from './misc/util'; type parserOptions = @@ -30,7 +30,7 @@ const useLocalStorage = ( : JSON.parse; // eslint-disable-next-line react-hooks/rules-of-hooks - const [state, setState] = useState(() => { + const initializer = useRef((key: string) => { try { const serializer = options ? (options.raw ? String : options.serializer) : JSON.stringify; @@ -49,6 +49,12 @@ const useLocalStorage = ( } }); + // eslint-disable-next-line react-hooks/rules-of-hooks + const [state, setState] = useState(() => initializer.current(key)); + + // eslint-disable-next-line react-hooks/rules-of-hooks + useLayoutEffect(() => setState(initializer.current(key)), [key]); + // eslint-disable-next-line react-hooks/rules-of-hooks const set: Dispatch> = useCallback( (valOrFunc) => { diff --git a/tests/useLocalStorage.test.ts b/tests/useLocalStorage.test.ts index 9f642ad6..1ec54dd6 100644 --- a/tests/useLocalStorage.test.ts +++ b/tests/useLocalStorage.test.ts @@ -80,6 +80,19 @@ describe(useLocalStorage, () => { expect(foo).toEqual('baz'); }); + it('reinitializes state when key changes', () => { + let key = 'foo'; + const { result, rerender } = renderHook(() => useLocalStorage(key, 'bar')); + + const [, setState] = result.current; + act(() => setState('baz')); + key = 'bar'; + rerender(); + + const [state] = result.current; + expect(state).toEqual('bar'); + }); + /* it('keeps multiple hooks accessing the same key in sync', () => { localStorage.setItem('foo', 'bar');