大家都看得懂的源码——如何封装cookie/localStorage/sessionStoragehook?我觉得还不错,点个关注支持一下,谢谢。今天我们就来看看ahooks是如何封装cookie/localStorage/sessionStorage的。cookieahooks封装了useCookieState,一个可以在Cookie中存储状态的Hook。这个钩子使用js-cookienpm库。我认为选择它的原因有以下几点:包装小。压缩后少于800字节。本身没有其他依赖项。这对于ahooks来说非常重要,它本来就是一个工具库。更好的兼容性。支持所有浏览器。并支持任意字符。当然它还有其他的特性,比如支持ESM/AMD/CommonJS导入等等。封装的代码并不复杂。我们先看看默认值的设置。优先级如下:如果本地cookie中已经存在该值,则直接取。如果设置的值为字符串,则直接返回。设置值为函数,执行函数,返回函数执行结果。返回选项中设置的默认值。const[state,setState]=useState(()=>{//如果有值,直接返回constcookieValue=Cookies.get(cookieKey);if(isString(cookieValue))returncookieValue;//定义Cookie默认值,但不同步到本地Cookie//可以自定义默认值if(isFunction(options.defaultValue)){returnoptions.defaultValue();}returnoptions.defaultValue;});看设置cookies的逻辑——updateState方法。在使用updateState方法时,开发人员可以传入新的选项——newOptions。合并操作将使用useCookieState设置的选项执行。最后除了defaultValue会透传给js-cookie的set方法的第三个参数。获取cookie的值,判断传入的值,如果是函数,则取执行后返回的结果,否则直接取值。如果该值未定义,请清除cookie。否则调用js-cookie的set方法。最后返回cookie的值以及如何设置。//设置cookie值constupdateState=useMemoizedFn((newValue:State|((prevState:State)=>State),newOptions:Cookies.CookieAttributes={},)=>{const{defaultValue,...restOptions}={...options,...newOptions};setState((prevState)=>{constvalue=isFunction(newValue)?newValue(prevState):newValue;//当值未定义时,清除cookieif(value===undefined){Cookies.remove(cookieKey);}else{Cookies.set(cookieKey,value,restOptions);}returnvalue;});},);return[state,updateState]asconst;localStorage/sessionStorageahooks封装useLocalStorageState并使用会话存储状态。挂钩以在localStorage和sessionStorage中存储状态。两者的用法是一样的,因为是用官方的方法来封装的。我们以useLocalStorageState为例。可以看到useLocalStorageState其实就是调用createUseStorageState方法返回的结果。这个方法的入口会判断是否是浏览器环境来决定是否使用localStorage,因为ahooks需要支持服务端渲染。import{createUseStorageState}from'../createUseStorageState';importisBrowserfrom'../utils/isBrowser';constuseLocalStorageState=createUseStorageState(()=>(isBrowser?localStorage:undefined));exportdefaultuseLocalStorageState;让我们关注它,createUseStorageState方法。先调用传入参数。如果报错,会及时捕获。这是因为:可以看出这里返回的storage其实可能是undefined的,后面会有catch处理。另外,从这个issue中我们可以看到,当cookie被禁用时,localStorage是无法访问的。Stackoverflow也有这个讨论。(又补充了奇怪的知识)exportfunctioncreateUseStorageState(getStorage:()=>Storage|undefined){functionuseStorageState(key:string,options?:Options){letstorage:Storage|undefined){不明确的;//https://github.com/alibaba/hooks/issues/800try{storage=getStorage();}catch(err){console.error(err);}//代码后面会解释}支持自定义序列化方法。如果没有,直接JSON.stringify。支持自定义反序列化方法。如果没有,直接JSON.parse。getStoredValue获取存储的默认值,如果本地没有值则返回默认值。更新传入键时,将重新分配值。//自定义序列化方法constserializer=(value:T)=>{if(options?.serializer){returnoptions?.serializer(value);}returnJSON.stringify(value);};//自定义反序列化方法constdeserializer=(value:string)=>{if(options?.deserializer){returnoptions?.deserializer(value);}returnJSON.parse(value);};functiongetStoredValue(){try{constraw=storage?.getItem(key);如果(原始){返回解串器(原始);}}catch(e){console.error(e);}//默认值if(isFunction(options?.defaultValue)){returnoptions?.defaultValue();}returnoptions?.defaultValue;}const[state,setState]=useState(()=>getStoredValue());//当key更新时执行useUpdateEffect(()=>{setState(getStoredValue());},[key]);最后,还有一个更新存储的函数:如果值未定义,则removeItem删除存储。如果是函数,执行后得到结果。否则,直接取值。//SetStateconstupdateState=(value?:T|IFuncUpdater)=>{//如果未定义,移除选项if(isUndef(value)){setState(undefined);存储?.removeItem(键);//如果是函数,则用于传入state并返回结果}elseif(isFunction(value)){constcurrentState=value(state);试试{setState(currentState);storage?.setItem(key,serializer(currentState));}catch(e){console.error(e);}}else{//设置值try{setState(value);存储?.setItem(键,序列化器(值));}catch(e){console.error(e);}}};总结归纳对cookie/localStorage/sessionStorage的封装是我们经常需要做的。ahooks的封装整体来说还是比较简单的,大家可以参考一下。本文已收录在我的个人博客中,欢迎关注~