在react中使用useSyncExternalStore做localStorage数据同步

使用useSyncExternalStore做状态持久化和标签页同步

useLocalStorage.ts

'use client'
import { useSyncExternalStore } from 'react'

export function useLocalStorage(key: string, initialValue?: unknown) {
  const getSnapshot = () => localStorage.getItem(key) as string
  const subscribe = (listener: () => void) => {
    window.addEventListener('storage', listener)
    return () => void window.removeEventListener('storage', listener)
  }

  const store = useSyncExternalStore(subscribe, getSnapshot)

  const setState = (v: unknown) => {
    const prevState = JSON.parse(store)
    const nextState = typeof v == 'function' ? v(prevState) : v

    window.localStorage.setItem(key, JSON.stringify(nextState))
    if (nextState) {
      window.dispatchEvent(
        new StorageEvent('storage', {
          key,
          newValue: JSON.stringify(nextState)
        })
      )
    }
  }

  return [store ? JSON.parse(store) : initialValue, setState] as const
}