自定义React localStorage hooks

1,299 阅读2分钟

在编写React项目时, 可能会存储一些状态, 比如说主题之类的, 在跨页面时如果要保持同一种状态, 可以使用最简单,实用的localStorage来完成.

localStorage

localStorage提供了键值对来进行存储和访问, 其中键和值都是字符串,在这里我们主要使用两个方法:

  • getItem, 传入一个key参数, 返回一个对应的值, 如果不存在值则返回null
  • setItem, 传入keyvalue两个参数, 会把value存储在key上

removeItem(删除制定的key对应的值)和clear(删除所有存储的指)这里用不到.

如果我们存储一个不是字符串的值, 要先使用JSON.stringify转换为字符串,获取到的值使用JSON.parse转换.

创建自定义hooks

现在我们来创建一个自定义的React Hooks函数, 自动将组件的状态保存到localStorage中,

创建一个useLocalStorageState函数, 函数有两个参数:

  • defaultValue, 获取key对应的值时为null, 使用默认参数
  • localStorageKey, 存储值的key
const useLocalStorageState = (defaultValue, localStorageKey) => {}

从localStorage获取值

正如上面提到的, 从localStorage中获取值, 使用JSON.parse进行转换,然后使用useState将值存储在内存中.

const useLocalStorageState = (defaultValue, localStorageKey) => {
    const [value, setValue] = useState(JSON.parse(localStorage.getItem(localStorageKey)));
}

但是这样还有问题, 我们获取的值可能为null,也可能是无效的,错误的JSON, 使用JSON.parse可能会有错误, 我们需要处理这些情况, 并返回默认值.修改一下代码:

const useLocalStorageState = (defaultValue, localStorageKey) => {
    const [value, setValue] = useState(() => {
        const itemValue = localStorage.getItem(localStorageKey);
        if(itemValue === null) return defaultValue;
        try{
            return JSON.parse(itemValue);
        }catch{
            return defaultValue;
        }
    });   
}

我们已经成功的获取了值, 现在我们需要在状态变化时, 更新localStorage中的值.

监听状态变化并更新localStorage中的值

每当value发生变化时,我们使用setItem, 传入localStorageKeyJSON.stringify转换后的值, 然后使用useEffect.

useEffect(() => {
    localStorage.setItem(localStorageKey, JSON.stringify(value));
}, [value])

但是请注意, 这里会有一个性能问题,localStorage是同步操作,意味着它会阻塞主线程, 目前来看, 数据都比较简单可以忽略不计, 但是如果当你存储大量数据时, 它会是一个隐患. 我们需要采取一下办法来改良, 比如, 不在value变化的时候更新, 而是采用定时的更新. 这里不做演示.

包装Hooks

const useLocalStorageState = (defaultValue, localStorageKey) => {
    const [value, setValue] = useState(() => {
        const itemValue = localStorage.getItem(localStorageKey);
        if(itemValue === null) return defaultValue;
        try{
            return JSON.parse(itemValue);
        }catch{
            return defaultValue;
        }
    }); 
    useEffect(() => {
        localStorage.setItem(localStorageKey, JSON.stringify(value));
    }, [value]);
    
    return [value, setValue];  
}