之所以講這篇文章主要是為了加深對 React hooks 的理解。
因此,先要學(xué)習(xí)如何抽象自定義 hooks。構(gòu)建屬于自己的 React hooks 工具庫。
且培養(yǎng)閱讀學(xué)習(xí)源碼的習(xí)慣,工具庫是一個對源碼閱讀不錯的選擇。
現(xiàn)在看下ahooks 是怎么封裝 cookie/localStorage/sessionStorage 的。
cookie
ahooks 封裝了 useCookieState,一個可以將狀態(tài)存儲在 Cookie 中的 Hook 。
該 hook 使用了js-cookie這個 npm 庫。為什么用它:
主要就是由于包體積小。壓縮后小于 800 字節(jié)。自身是沒有其它依賴的。這對于原本就是一個工具庫的 ahooks 來講是很重要的。而且它擁有更好的兼容性。支持所有的瀏覽器。并支持任意的字符。
除此之外,它還有其他的特點(diǎn),比如支持 ESM/AMD/CommonJS 方式導(dǎo)入等等。
封裝的代碼并不復(fù)雜,先看默認(rèn)值的設(shè)置,其優(yōu)先級如下:
本地 cookie 中已有該值,則直接取。
設(shè)置的值為字符串,則直接返回。
設(shè)置的值為函數(shù),執(zhí)行該函數(shù),返回函數(shù)執(zhí)行結(jié)果。
返回 options 中設(shè)置的 defaultValue。
const [state, setState] = useState<State>(() => { // 假如有值,則直接返回 const cookieValue = Cookies.get(cookieKey); if (isString(cookieValue)) return cookieValue; // 定義 Cookie 默認(rèn)值,但不同步到本地 Cookie // 可以自定義默認(rèn)值 if (isFunction(options.defaultValue)) { return options.defaultValue(); } return options.defaultValue; });
再看設(shè)置 cookie 的邏輯 ——updateState方法。
在使用updateState方法的時候,開發(fā)者可以傳入新的 options —— newOptions。會與 useCookieState 設(shè)置的 options 進(jìn)行 merge 操作。最后除了 defaultValue 會透傳給 js-cookie 的 set 方法的第三個參數(shù)。
獲取到 cookie 的值,判斷傳入的值,假如是函數(shù),則取執(zhí)行后返回的結(jié)果,否則直接取該值。
如果值為 undefined,則清除 cookie。否則,調(diào)用 js-cookie 的 set 方法。
最終返回 cookie 的值以及設(shè)置的方法。
// 設(shè)置 Cookie 值 const updateState = useMemoizedFn( ( newValue: State | ((prevState: State) => State), newOptions: Cookies.CookieAttributes = {}, ) => { const { defaultValue, ...restOptions } = { ...options, ...newOptions }; setState((prevState) => { const value = isFunction(newValue) ? newValue(prevState) : newValue; // 值為 undefined 的時候,清除 cookie if (value === undefined) { Cookies.remove(cookieKey); } else { Cookies.set(cookieKey, value, restOptions); } return value; }); }, ); return [state, updateState] as const; localStorage/sessionStorage
ahooks 封裝了 useLocalStorageState 和 useSessionStorageState。將狀態(tài)存儲在 localStorage 和 sessionStorage 中的 Hook 。
兩者的使用方法是一樣的?,F(xiàn)在來說說 useLocalStorageState 。
useLocalStorageState就是用來調(diào)用 createUseStorageState 方法返回的結(jié)果。該方法的入?yún)袛嗍欠駷闉g覽器環(huán)境,以決定是否使用 localStorage,原因在于 ahooks 需要支持服務(wù)端渲染?!?/p>
import { createUseStorageState } from '../createUseStorageState'; import isBrowser from '../utils/isBrowser'; const useLocalStorageState = createUseStorageState(() => (isBrowser ? localStorage : undefined)); export default useLocalStorageState;
我們重點(diǎn)關(guān)注一下,createUseStorageState 方法。
先是調(diào)用傳入的參數(shù)。假如報錯會及時 catch。這是因為:
這里返回的 storage 可以看到其實(shí)可能是 undefined 的,后面都會有 catch 的處理。
另外,從這個issue中可以看到 cookie 被 disabled 的時候,也是訪問不了 localStorage 的。stackoverflow也有這個討論。(奇怪的知識又增加了)
export function createUseStorageState(getStorage: () => Storage | undefined) { function useStorageState<T>(key: string, options?: Options<T>) { let storage: Storage | undefined; // https://github.com/alibaba/hooks/issues/800 try { storage = getStorage(); } catch (err) { console.error(err); } // 代碼在后面講解 }
支持自定義序列化方法。沒有則直接 JSON.stringify。
支持自定義反序列化方法。沒有則直接 JSON.parse。
getStoredValue 獲取 storage 的默認(rèn)值,如果本地沒有值,則返回默認(rèn)值。
當(dāng)傳入 key 更新的時候,重新賦值。
// 自定義序列化方法 const serializer = (value: T) => { if (options?.serializer) { return options?.serializer(value); } return JSON.stringify(value); }; // 自定義反序列化方法 const deserializer = (value: string) => { if (options?.deserializer) { return options?.deserializer(value); } return JSON.parse(value); }; function getStoredValue() { try { const raw = storage?.getItem(key); if (raw) { return deserializer(raw); } } catch (e) { console.error(e); } // 默認(rèn)值 if (isFunction(options?.defaultValue)) { return options?.defaultValue(); } return options?.defaultValue; } const [state, setState] = useState<T | undefined>(() => getStoredValue()); // 當(dāng) key 更新的時候執(zhí)行 useUpdateEffect(() => { setState(getStoredValue()); }, [key]);
最后是更新 storage 的函數(shù):
如果是值為 undefined,則 removeItem,移除該 storage。
如果為函數(shù),則取執(zhí)行后結(jié)果。
否則,直接取值。
// 設(shè)置 State const updateState = (value?: T | IFuncUpdater<T>) => { // 如果是 undefined,則移除選項 if (isUndef(value)) { setState(undefined); storage?.removeItem(key); // 如果是function,則用來傳入 state,并返回結(jié)果 } else if (isFunction(value)) { const currentState = value(state); try { setState(currentState); storage?.setItem(key, serializer(currentState)); } catch (e) { console.error(e); } } else { // 設(shè)置值 try { setState(value); storage?.setItem(key, serializer(value)); } catch (e) { console.error(e); } } };
總結(jié)與歸納
對 cookie/localStorage/sessionStorage 的封裝在日常開發(fā)中多次用到,其實(shí)ahooks 的封裝整體比較簡,但在簡單內(nèi)容要會才可以。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/128215.html
摘要:顧名思義,確實(shí)非常小,它的大小限制為左右,是網(wǎng)景公司的前雇員在年月的發(fā)明。是標(biāo)準(zhǔn)中新加入的技術(shù),它并不是什么劃時代的新東西。特性與的接口類似,但保存數(shù)據(jù)的生命周期與不同。但當(dāng)頁面關(guān)閉后,中的數(shù)據(jù)就會被清空。 本文最初發(fā)布于我的個人博客:咀嚼之味 最近在找暑期實(shí)習(xí),其中百度、網(wǎng)易游戲、阿里的面試都問到一些關(guān)于HTML5的東西,問題大多是這樣開頭的:你用過什么HTML5的技術(shù)呀?...
摘要:的區(qū)別及用法是本地存儲,存儲在客戶端,包括和。僅在當(dāng)前會話下有效,關(guān)閉頁面或瀏覽器后被清除。源生接口可以接受,亦可再次封裝來對和有更好的支持。但需要程序員自己封裝,源生的接口不友好。每個最多只能有條,每個長度不能超過。 localStorage、sessionStorage、Cookie的區(qū)別及用法 showImg(https://segmentfault.com/img/bVYLlH...
摘要:之前只知道的一些存儲量,過期時間上的區(qū)別,今天仔細(xì)研究了一下它們用法上的區(qū)別。這個限制確保了儲存在中的信息只能讓批準(zhǔn)的接受者訪問,而無法被其他域訪問。中所有的名字和值都是經(jīng)過編碼的,所以必須使用來解碼。屬于永久性存儲。 之前只知道cookie、sessionStorage、localStorage的一些存儲量,過期時間上的區(qū)別,今天仔細(xì)研究了一下它們用法上的區(qū)別。 cookie coo...
摘要:快速上手先說區(qū)別數(shù)據(jù)大小不能超過??梢栽诤蠖嗽O(shè)置修改,數(shù)據(jù)僅在本地瀏覽器保存。數(shù)據(jù)存儲在瀏覽器僅在瀏覽器為關(guān)閉的狀態(tài),關(guān)閉窗口后數(shù)據(jù)就會銷毀。默認(rèn)情況下,屬于當(dāng)前頁面。 cookie、Sessionstorage、Localstorage快速上手 先說區(qū)別 cookie: 數(shù)據(jù)大小不能超過4KB。 不管是否有需求,cookie數(shù)據(jù)都會在HTTP請求中攜帶,在瀏覽器和服務(wù)器中來回傳遞,...
閱讀 596·2023-03-27 18:33
閱讀 790·2023-03-26 17:27
閱讀 684·2023-03-26 17:14
閱讀 645·2023-03-17 21:13
閱讀 573·2023-03-17 08:28
閱讀 1895·2023-02-27 22:32
閱讀 1376·2023-02-27 22:27
閱讀 2280·2023-01-20 08:28