最近在项目中做一个交互优化:需要记录用户最近搜索的关键字
如何封装一个 localStorage hooks,方便后期调用呢?
import React from 'react';
const useStateWithLocalStorage = (key, initVal) => {
const localStr = localStorage.getItem(key);
const [value, setValue] = React.useState(localStr || initVal);
React.useEffect(() => {
localStorage.setItem(key, value);
}, [value]);
return [value, setValue];
};
export default useStateWithLocalStorage;
上面几行代码,其实就可以满足基本的需求了。但是 initVal 只能支持字符串,如果想要使用数组或对象就会有麻烦了。
原因在于 localStorage 中的键值对总是以字符串的形式存储。 需要注意, 和js对象相比, 键值对总是以字符串的形式存储,意味着数值类型会自动转化为字符串类型。
也就是说如果 initVal 如果是对象,在存储时会被转化为 [Object object],这个过程叫做序列化。因此在取值时需要使用反序列化将字符串转换为原来的数据格式。
const useStateWithLocalStorage = (key, initVal) => {
let preStr;
try {
let localStr = localStorage.getItem(key);
preStr = JSON.parse(localStr as string); // 取值时反序列化
} catch (error) {
console.error('localStorage:>> ', error);
}
let [value, setValue] = React.useState(preStr || initVal);
React.useEffect(() => {
localStorage.setItem(String(key), JSON.stringify(value)); // 存储时序列化
}, [value]);
return [value, setValue];
};
export default useStateWithLocalStorage;
以上就可以支持数组、对象等数据格式了,但是要注意的是,key 必须是 string,否则会出现键值对覆盖的情况。因此需要检测 key 的类型,并及时抛错。
const useStateWithLocalStorage = (key, initVal) => {
if (typeof key !== 'string') {
throw new Error('key must be a string');
}
let preStr;
...
};
export default useStateWithLocalStorage;
以上,就是对 useLocalStorage 的封装过程,附上完成代码:
import React from 'react';
/**
* localStorage 持久化数据
*
* @param {*} key
* @param {*} initVal 初始值,支持数组,对象
* @return {*}
*/
const useStateWithLocalStorage = (key, initVal) => {
if (typeof key !== 'string') {
throw new Error('key must be a string');
}
let preStr;
try {
let localStr = localStorage.getItem(key);
if (localStr === undefined) {
localStr = null; // 避免解析时报错,SyntaxError
}
preStr = JSON.parse(localStr as string); // 反序列化
} catch (error) {
console.error('useStateWithLocalStorage :>> ', error);
}
let [value, setValue] = React.useState(preStr || initVal);
React.useEffect(() => {
localStorage.setItem(String(key), JSON.stringify(value)); // 序列化
}, [value]);
return [value, setValue];
};
export default useStateWithLocalStorage;
小结
这个场景主要考察了 localStorage 键值对的「隐式」转换,如何解决转换的问题,以及 JSON 解析过程中一些莫名其妙的报错,如:
VM733:1 Uncaught SyntaxError: Unexpected token o in JSON at position 0
localStorage 的使用是有一些小坑,对前端的基本知识也还是有一些考验的。