1- import { useEffect , useState } from "react"
1+ import { useCallback , useSyncExternalStore } from "react"
22
33import { LocalStorageKeys } from "@app/utils/defaults"
44
@@ -11,38 +11,49 @@ export type Storable =
1111 | Storable [ ]
1212 | { [ key : string ] : Storable }
1313
14- function coerce < T extends Storable > (
15- value : string ,
16- { fallback } : { fallback : T }
17- ) : T {
18- try {
19- return JSON . parse ( value ) as T
20- } catch ( e ) {
21- console . error ( e )
22- return fallback
23- }
14+ type KeyValue = ( typeof LocalStorageKeys ) [ keyof typeof LocalStorageKeys ]
15+
16+ type UpdateEventPayload = {
17+ key : string
2418}
2519
26- type KeyValue = ( typeof LocalStorageKeys ) [ keyof typeof LocalStorageKeys ]
20+ export class StorageUpdateEvent extends CustomEvent < UpdateEventPayload > {
21+ static type : keyof WindowEventMap = "rsseditor:storage-update" as const
22+
23+ constructor ( payload : UpdateEventPayload ) {
24+ super ( StorageUpdateEvent . type , { detail : payload } )
25+ }
26+ }
2727
2828export default function useLocalStorage < T extends Storable > (
2929 key : KeyValue ,
3030 initialValue : T
31- ) : [ T , React . Dispatch < React . SetStateAction < T > > ] {
32- const [ value , setValue ] = useState ( ( ) => {
33- if ( ! window . localStorage ) return initialValue
34-
35- const currentValue = localStorage . getItem ( key )
36- return currentValue
37- ? coerce < T > ( currentValue , { fallback : initialValue } )
38- : initialValue
39- } )
40-
41- useEffect ( ( ) => {
42- if ( window . localStorage ) {
31+ ) : [ T , ( newValue : T ) => void ] {
32+ const currentStoredItem = useSyncExternalStore (
33+ ( callback ) => {
34+ const listener = ( evt : StorageUpdateEvent ) => {
35+ if ( evt . detail . key === key ) callback ( )
36+ }
37+
38+ window . addEventListener ( "rsseditor:storage-update" , listener )
39+ return ( ) => {
40+ window . removeEventListener ( "rsseditor:storage-update" , listener )
41+ }
42+ } ,
43+ ( ) => localStorage . getItem ( key )
44+ )
45+
46+ const setStoredValue = useCallback (
47+ ( value : T ) => {
4348 localStorage . setItem ( key , JSON . stringify ( value ) )
44- }
45- } , [ key , value ] )
49+ window . dispatchEvent ( new StorageUpdateEvent ( { key } ) )
50+ } ,
51+ [ key ]
52+ )
53+
54+ const value : T = currentStoredItem
55+ ? JSON . parse ( currentStoredItem )
56+ : initialValue
4657
47- return [ value , setValue ]
58+ return [ value , setStoredValue ]
4859}
0 commit comments