在编写React项目时, 可能会存储一些状态, 比如说主题之类的, 在跨页面时如果要保持同一种状态, 可以使用最简单,实用的localStorage
来完成.
localStorage
localStorage
提供了键值对来进行存储和访问, 其中键和值都是字符串,在这里我们主要使用两个方法:
getItem
, 传入一个key
参数, 返回一个对应的值, 如果不存在值则返回null
setItem
, 传入key
和value
两个参数, 会把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
, 传入localStorageKey
和JSON.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];
}