Skip to content

Commit cfcd652

Browse files
committed
feat: add a faster mode to useLocalStorage via priority flag
1 parent 6194913 commit cfcd652

File tree

2 files changed

+18
-6
lines changed

2 files changed

+18
-6
lines changed

packages/usehooks-ts/src/useLocalStorage/useLocalStorage.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
Persist the state with [local storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) so that it remains after a page refresh. This can be useful for a dark theme.
22
This hook is used in the same way as useState except that you must pass the storage key in the 1st parameter.
33

4-
You can also pass an optional third parameter to use a custom serializer/deserializer.
4+
You can also pass an optional third parameter to use a custom serializer/deserializer or to set the priority of sync activities.
5+
6+
For example, with `{ priority: 'max' }`, the hook will use `useLayoutEffect` to ensure the most rapid update; ideal for persisted UI settings that affect initial render and the page layout.
57

68
**Note**: If you use this hook in an SSR context, set the `initializeWithValue` option to `false`, it will initialize in SSR with the initial value.
79

packages/usehooks-ts/src/useLocalStorage/useLocalStorage.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useCallback, useEffect, useState } from 'react'
1+
import { useCallback, useEffect, useLayoutEffect, useState } from 'react'
22

33
import type { Dispatch, SetStateAction } from 'react'
44

@@ -26,6 +26,13 @@ type UseLocalStorageOptions<T> = {
2626
* @default true
2727
*/
2828
initializeWithValue?: boolean
29+
/**
30+
* If 'max', useLayoutEffect will be used to ensure the most rapid update; ideal for
31+
* UI settings that affect initial render and the page layout.
32+
* If 'default', useEffect will be used to gracefully update without blocking the UI.
33+
* @default 'default'
34+
*/
35+
priority?: 'max' | 'default'
2936
}
3037

3138
const IS_SERVER = typeof window === 'undefined'
@@ -165,10 +172,13 @@ export function useLocalStorage<T>(
165172
window.dispatchEvent(new StorageEvent('local-storage', { key }))
166173
})
167174

168-
useEffect(() => {
169-
setStoredValue(readValue())
170-
// eslint-disable-next-line react-hooks/exhaustive-deps
171-
}, [key])
175+
const effectCallback = useCallback(() => setStoredValue(readValue()), [])
176+
177+
if (!IS_SERVER && options.priority === 'max' ) {
178+
useLayoutEffect(effectCallback, [key])
179+
} else {
180+
useEffect(effectCallback, [key])
181+
}
172182

173183
const handleStorageChange = useCallback(
174184
(event: StorageEvent | CustomEvent) => {

0 commit comments

Comments
 (0)