@@ -791,59 +791,70 @@ export function useList(defaultList = []) {
791791 return [ list , { set, push, removeAt, insertAt, updateAt, clear } ] ;
792792}
793793
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+
794822export function useLocalStorage ( key , initialValue ) {
795- if ( getEnvironment ( ) === "server" ) {
796- throw Error ( "useLocalStorage is a client-side only hook." ) ;
797- }
823+ const getSnapshot = ( ) => getLocalStorageItem ( key ) ;
798824
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+ ) ;
808830
809- const [ localState , setLocalState ] = React . useState ( readValue ) ;
810- const handleSetState = React . useCallback (
811- ( value ) => {
831+ const setState = React . useCallback (
832+ ( v ) => {
812833 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+ }
817841 } catch ( e ) {
818842 console . warn ( e ) ;
819843 }
820844 } ,
821- [ key , localState ]
845+ [ key , store ]
822846 ) ;
823847
824- const onStorageChange = React . useEffectEvent ( ( ) => {
825- setLocalState ( readValue ( ) ) ;
826- } ) ;
827-
828848 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 ] ) ;
838856
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 ] ;
847858}
848859
849860export function useLogger ( name , ...rest ) {
0 commit comments