@@ -791,59 +791,70 @@ export function useList(defaultList = []) {
791
791
return [ list , { set, push, removeAt, insertAt, updateAt, clear } ] ;
792
792
}
793
793
794
+ const dispatchStorageEvent = ( key , newValue ) => {
795
+ window . dispatchEvent ( new StorageEvent ( "storage" , { key, newValue } ) ) ;
796
+ } ;
797
+
798
+ const setLocalStorageItem = ( key , value ) => {
799
+ const stringifiedValue = JSON . stringify ( value ) ;
800
+ window . localStorage . setItem ( key , stringifiedValue ) ;
801
+ dispatchStorageEvent ( key , stringifiedValue ) ;
802
+ } ;
803
+
804
+ const removeLocalStorageItem = ( key ) => {
805
+ window . localStorage . removeItem ( key ) ;
806
+ dispatchStorageEvent ( key , null ) ;
807
+ } ;
808
+
809
+ const getLocalStorageItem = ( key ) => {
810
+ return window . localStorage . getItem ( key ) ;
811
+ } ;
812
+
813
+ const useLocalStorageSubscribe = ( callback ) => {
814
+ window . addEventListener ( "storage" , callback ) ;
815
+ return ( ) => window . removeEventListener ( "storage" , callback ) ;
816
+ } ;
817
+
818
+ const getLocalStorageServerSnapshot = ( ) => {
819
+ throw Error ( "useLocalStorage is a client-only hook" ) ;
820
+ } ;
821
+
794
822
export function useLocalStorage ( key , initialValue ) {
795
- if ( getEnvironment ( ) === "server" ) {
796
- throw Error ( "useLocalStorage is a client-side only hook." ) ;
797
- }
823
+ const getSnapshot = ( ) => getLocalStorageItem ( key ) ;
798
824
799
- const readValue = React . useCallback ( ( ) => {
800
- try {
801
- const item = window . localStorage . getItem ( key ) ;
802
- return item ? JSON . parse ( item ) : initialValue ;
803
- } catch ( error ) {
804
- console . warn ( error ) ;
805
- return initialValue ;
806
- }
807
- } , [ key , initialValue ] ) ;
825
+ const store = React . useSyncExternalStore (
826
+ useLocalStorageSubscribe ,
827
+ getSnapshot ,
828
+ getLocalStorageServerSnapshot
829
+ ) ;
808
830
809
- const [ localState , setLocalState ] = React . useState ( readValue ) ;
810
- const handleSetState = React . useCallback (
811
- ( value ) => {
831
+ const setState = React . useCallback (
832
+ ( v ) => {
812
833
try {
813
- const nextState =
814
- typeof value === "function" ? value ( localState ) : value ;
815
- window . localStorage . setItem ( key , JSON . stringify ( nextState ) ) ;
816
- setLocalState ( nextState ) ;
834
+ const nextState = typeof v === "function" ? v ( JSON . parse ( store ) ) : v ;
835
+
836
+ if ( nextState === undefined || nextState === null ) {
837
+ removeLocalStorageItem ( key ) ;
838
+ } else {
839
+ setLocalStorageItem ( key , nextState ) ;
840
+ }
817
841
} catch ( e ) {
818
842
console . warn ( e ) ;
819
843
}
820
844
} ,
821
- [ key , localState ]
845
+ [ key , store ]
822
846
) ;
823
847
824
- const onStorageChange = React . useEffectEvent ( ( ) => {
825
- setLocalState ( readValue ( ) ) ;
826
- } ) ;
827
-
828
848
React . useEffect ( ( ) => {
829
- window . addEventListener ( "storage" , onStorageChange ) ;
830
-
831
- return ( ) => {
832
- window . removeEventListener ( "storage" , onStorageChange ) ;
833
- } ;
834
- } , [ ] ) ;
835
-
836
- return [ localState , handleSetState ] ;
837
- }
849
+ if (
850
+ getLocalStorageItem ( key ) === null &&
851
+ typeof initialValue !== "undefined"
852
+ ) {
853
+ setLocalStorageItem ( key , initialValue ) ;
854
+ }
855
+ } , [ key , initialValue ] ) ;
838
856
839
- export function useLockBodyScroll ( ) {
840
- React . useEffect ( ( ) => {
841
- const originalStyle = window . getComputedStyle ( document . body ) . overflow ;
842
- document . body . style . overflow = "hidden" ;
843
- return ( ) => {
844
- document . body . style . overflow = originalStyle ;
845
- } ;
846
- } , [ ] ) ;
857
+ return [ store ? JSON . parse ( store ) : initialValue , setState ] ;
847
858
}
848
859
849
860
export function useLogger ( name , ...rest ) {
0 commit comments