All files / react useLocalStorage.ts

86.36% Statements 19/22
75% Branches 3/4
80% Functions 4/5
86.36% Lines 19/22

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63                                            8x 2x 2x 2x     2x           8x   8x 8x 8x   8x       8x   4x 2x   4x 4x         8x 2x 2x     8x    
import { Dispatch, SetStateAction, useCallback, useState } from 'react'
import { useLatest, useUpdateEffect } from 'react-use'
 
export type UseLocalStorageResult<S> = readonly [
  S,
  Dispatch<SetStateAction<S>>,
  () => void,
]
 
export function useLocalStorage<S>(
  key: string,
): UseLocalStorageResult<S | undefined>
 
export function useLocalStorage<S>(
  key: string,
  initialState: S,
): UseLocalStorageResult<S>
 
export function useLocalStorage<S>(
  key: string,
  initialState?: S,
): UseLocalStorageResult<S | undefined> {
  const getLocalStorageItem = useCallback(() => {
    try {
      const data = localStorage.getItem(key)
      Iif (data != null) {
        return JSON.parse(data)
      }
      return initialState
    } catch {
      return initialState
    }
  }, [key, initialState])
 
  const [state, setState] = useState(getLocalStorageItem)
 
  const latestKey = useLatest(key)
  const latestInitialState = useLatest(initialState)
  const latestState = useLatest(state)
 
  useUpdateEffect(() => {
    setState(getLocalStorageItem())
  }, [key])
 
  const set: UseLocalStorageResult<S | undefined>[1] = useCallback(
    nextState => {
      if (typeof nextState === 'function') {
        nextState = (nextState as any)(latestState.current)
      }
      setState(nextState)
      localStorage.setItem(latestKey.current, JSON.stringify(nextState))
    },
    [],
  )
 
  const reset: UseLocalStorageResult<S | undefined>[2] = useCallback(() => {
    localStorage.removeItem(latestKey.current)
    setState(latestInitialState.current)
  }, [])
 
  return [state, set, reset]
}