实战指南:封装localStorge

本文是《React管理平台》第六节

原生的 localStorage 接口并不支持存储复杂数据类型。为了解决这些问题,本文将介绍高效、安全的封装 localStorage 的方法。

我们封装的localStorage.ts文件

我们在src/utils目录中创建localStorage.ts文件,该文件的代码为:

ts 复制代码
// localStorage.ts
type Storable = string | number | boolean | null | { [key: string]: Storable } | Storable[]

function checkKey(key: string, action: string) {
  if (!key) {
    throw new Error(`${action}操作失败:缺少key`)
  }
}

export default {
  set(key: string, value: Storable) {
    checkKey(key, 'set')

    if (typeof value === 'undefined') {
      throw new Error(`${key}值为undefined`)
    }

    let valueToStore: string

    switch (typeof value) {
      case 'object':
        if (value === null) {
          valueToStore = 'null'
        } else {
          valueToStore = JSON.stringify(value)
        }
        break
      default:
        valueToStore = value.toString()
    }

    localStorage.setItem(key, valueToStore)
  },

  get<T extends Storable = Storable>(key: string): T | undefined {
    checkKey(key, 'get')

    const rawValue = localStorage.getItem(key)

    if (!rawValue) {
      return undefined
    }

    try {
      if (rawValue === 'true') return true as never as T
      if (rawValue === 'false') return false as never as T
      if (rawValue === 'null') return null as never as T
      return JSON.parse(rawValue) as T
    } catch (error) {
      if (error instanceof SyntaxError) {
        return rawValue as never as T
      }
      throw error
    }
  },

  remove(key: string) {
    checkKey(key, 'remove')

    localStorage.removeItem(key)
  },

  clear(): void {
    localStorage.clear()
  },

  getAllKeys(): string[] {
    return Object.keys(localStorage)
  },

  has(key: string) {
    checkKey(key, 'has')

    return localStorage.getItem(key) !== null
  }
}

了解localStorage

我们回顾一下localStorage的基础知识:localStorage是一种Web存储功能,它允许网页在用户浏览器中存储键值对信息。这些数据不会随着浏览器关闭而失效,而是长期存在。

功能封装:优雅的操作接口

封装的目的在于简化操作,提高代码的可读性与可维护性。接下来我们就具体看看如何封装localStorage的基本操作。

键值检查

javascript 复制代码
function checkKey(key: string, action: string) {
  if (!key) {
    throw new Error(`${action}操作失败:缺少key`)
  }
}

在进行任何操作之前,我们通过checkKey方法来确保所需的key值存在。如果key值缺失,会抛出错误。

数据设置:灵活存储多种数据类型

set方法允许存储字符串、数字、布尔值、null,甚至是对象或数组(作为JSON字符串存储)。在存储前会对值进行检查和转换,保证数据准确存入localStorage。

javascript 复制代码
set(key: string, value: Storable) {
  if (typeof value === 'undefined') {
      throw new Error(`${key}值为undefined`)
    }

    let valueToStore: string

    switch (typeof value) {
      case 'object':
        if (value === null) {
          valueToStore = 'null'
        } else {
          valueToStore = JSON.stringify(value)
        }
        break
      default:
        valueToStore = value.toString()
    }
    // ...
}

数据获取

get方法通过解析返回原始的数据类型。如果数据并非true、false、null或JSON格式,则直接返回。

javascript 复制代码
get<T extends Storable = Storable>(key: string): T | undefined {
  // 省略的参数检查代码
  try {
      if (rawValue === 'true') return true as never as T
      if (rawValue === 'false') return false as never as T
      if (rawValue === 'null') return null as never as T
      return JSON.parse(rawValue) as T
    } catch (error) {
      if (error instanceof SyntaxError) {
        return rawValue as never as T
      }
      throw error
    }
}

数据移除:简单删除指定键值

remove方法提供了移除某个特定的存储项操作。

javascript 复制代码
remove(key: string) {
  // 省略的参数检查代码
  localStorage.removeItem(key)
}

清空数据:一键清除所有存储

clear方法用于清除localStorage中的所有数据,为应用提供了快速的数据重置方式。

其他辅助方法:提高查询效率

我们还提供了getAllKeyshas方法,分别用于获取所有存储的键和检查特

使用自定义的localStorage工具进行数据管理

接下来我们测试封装的localStorage方法

设置本地存储

测试使用 set 方法:

tsx 复制代码
import storage from '@/utils/localStorage.ts'

export const Welcome = () => {
  function handleSetLocalStorage() {
    storage.set('string', '辰火流光')

    storage.set('number', 666)

    storage.set('json', { name: '辰火流光', age: 30 })

    storage.set('numberArray', [1, 2, 3])

    storage.set('stringArray', ['a', 'b', 'c'])

    storage.set('array', [
      { name: '辰火流光', age: 30 },
      { name: '辰火流光', age: 30 },
      { name: '辰火流光', age: 30 }
    ])

    storage.set('null', null)

    // storage.set('error', undefined)


    storage.set('boolean', true)
  }

  return (
    <div>
      <button onClick={handleSetLocalStorage}>setLocalStorage</button>
    </div>
  )
}

成功执行上述代码后,在浏览器的localStorage中可以看到相应的键值对。

代码storage.set('error', undefined)会报错:Uncaught Error: error值为undefined 因为我们限制了值不能为undefined,而错误中提示的error其实是调用该方法的key名称

读取本地存储

测试使用 get 方法:

tsx 复制代码
import storage from '@/utils/localStorage.ts'

export const Welcome = () => {
  function handleGetLocalStorage() {
    console.log(storage.get('string'))
    console.log(typeof storage.get('string'))

    console.log(storage.get('number'))
    console.log(typeof storage.get('number'))

    console.log(storage.get('json'))
    console.log(typeof storage.get('json'))

    console.log(storage.get('numberArray'))
    console.log(typeof storage.get('numberArray'))

    console.log(storage.get('stringArray'))
    console.log(typeof storage.get('stringArray'))

    console.log(storage.get('array'))
    console.log(typeof storage.get('array'))

    console.log(storage.get('null'))
    console.log(typeof storage.get('null'))

    console.log(storage.get('boolean'))
    console.log(typeof storage.get('boolean'))

    console.log(storage.get('不存在的key'))
    console.log(typeof storage.get('不存在的key'))
  }

  return (
    <div>
      <button onClick={handleGetLocalStorage}>getLocalStorage</button>
    </div>
  )
}

在浏览器控制台,我们看到从storage.get返回的值及其对应的数据类型。如果查询一个不存在的键,则返回undefined

删除和清空本地存储

我们也来看看如何删除特定键 和如何清除整个localStorage

tsx 复制代码
import storage from '@/utils/localStorage.ts'

export const Welcome = () => {
  function handleRemoveClick() {
    storage.remove('string')
  }

  function handleClearClick() {
    storage.clear()
  }

  return (
    <div>
      <button onClick={handleRemoveClick}>remove</button>
      <button onClick={handleClearClick}>clear</button>
    </div>
  )
}

执行上述代码后,会看到对应的键值对从浏览器的localStorage中被删除全部清空

相关推荐
铭毅天下1 分钟前
EasySearch Rules 规则语法速查手册
开发语言·前端·javascript·ecmascript
GISer_Jing13 分钟前
AI Agent操作系统架构师:Harness Engineer解析
前端·人工智能·ai·aigc
英俊潇洒美少年21 分钟前
css中专门用来提升渲染性能、减少重排重绘的属性
前端·css
天若有情67335 分钟前
前端HTML精讲01:别再乱 div 一把抓,吃透语义化标签才是进阶第一步
前端·html
Highcharts.js36 分钟前
React 开发者的图表库生态:Highcharts React
前端·react.js·前端框架
阿部多瑞 ABU36 分钟前
文明文化悖论
前端·人工智能·ai写作
钛态1 小时前
Flutter 三方库 react 泛前端核心范式框架鸿蒙原生层生态级双向超能适配:跨时空重塑响应式单向数据流拓扑与高度精密生命周期树引擎解耦视图渲染控制中枢(适配鸿蒙 HarmonyOS ohos)
前端·flutter·react.js
全栈前端老曹1 小时前
【前端地图】地图开发基础概念——地图服务类型(矢量图、卫星图、地形图)、WGS84 / GCJ-02 / BD09 坐标系、地图 SDK 简介
前端·javascript·地图·wgs84·gcj-02·bd09·地图sdk
只与明月听1 小时前
RAG深入学习之向量数据库
前端·人工智能·python
吕不说1 小时前
AI 面试总挂?可能是表达出了问题:三层表达法 + STAR 进阶框架
前端