摘要:可以看到,這樣不僅沒(méi)有占用組件自己的,也不需要手寫(xiě)回調(diào)函數(shù)進(jìn)行處理,這些處理都?jí)嚎s成了一行。效果通過(guò)拿到周期才執(zhí)行的回調(diào)函數(shù)。實(shí)現(xiàn)等價(jià)于的回調(diào)僅執(zhí)行一次時(shí),因此直接把回調(diào)函數(shù)拋出來(lái)即可。
1 引言
上周的 精讀《React Hooks》 已經(jīng)實(shí)現(xiàn)了對(duì) React Hooks 的基本認(rèn)知,也許你也看了 React Hooks 基本實(shí)現(xiàn)剖析(就是數(shù)組),但理解實(shí)現(xiàn)原理就可以用好了嗎?學(xué)的是知識(shí),而用的是技能,看別人的用法就像刷抖音一樣(哇,飯還可以這樣吃?),你總會(huì)有新的收獲。
這篇文章將這些知識(shí)實(shí)踐起來(lái),看看廣大程序勞動(dòng)人民是如何發(fā)掘 React Hooks 的潛力的(造什么輪子)。
首先,站在使用角度,要理解 React Hooks 的特點(diǎn)是 “非常方便的 Connect 一切”,所以無(wú)論是數(shù)據(jù)流、Network,或者是定時(shí)器都可以監(jiān)聽(tīng),有一點(diǎn) RXJS 的意味,也就是你可以利用 React Hooks,將 React 組件打造成:任何事物的變化都是輸入源,當(dāng)這些源變化時(shí)會(huì)重新觸發(fā) React 組件的 render,你只需要挑選組件綁定哪些數(shù)據(jù)源(use 哪些 Hooks),然后只管寫(xiě) render 函數(shù)就行了!
2 精讀參考了部分 React Hooks 組件后,筆者按照功能進(jìn)行了一些分類(lèi)。
由于 React Hooks 并不是非常復(fù)雜,所以就不按照技術(shù)實(shí)現(xiàn)方式去分類(lèi)了,畢竟技術(shù)總有一天會(huì)熟練,而且按照功能分類(lèi)才有持久的參考價(jià)值。DOM 副作用修改 / 監(jiān)聽(tīng)
做一個(gè)網(wǎng)頁(yè),總有一些看上去和組件關(guān)系不大的麻煩事,比如修改頁(yè)面標(biāo)題(切換頁(yè)面記得改成默認(rèn)標(biāo)題)、監(jiān)聽(tīng)頁(yè)面大小變化(組件銷(xiāo)毀記得取消監(jiān)聽(tīng))、斷網(wǎng)時(shí)提示(一層層裝飾器要堆成小山了)。而 React Hooks 特別擅長(zhǎng)做這些事,造這種輪子,大小皆宜。
由于 React Hooks 降低了高階組件使用成本,那么一套生命周期才能完成的 “雜耍” 將變得非常簡(jiǎn)單。
下面舉幾個(gè)例子:
修改頁(yè)面 title效果:在組件里調(diào)用 useDocumentTitle 函數(shù)即可設(shè)置頁(yè)面標(biāo)題,且切換頁(yè)面時(shí),頁(yè)面標(biāo)題重置為默認(rèn)標(biāo)題 “前端精讀”。
useDocumentTitle("個(gè)人中心");
實(shí)現(xiàn):直接用 document.title 賦值,不能再簡(jiǎn)單。在銷(xiāo)毀時(shí)再次給一個(gè)默認(rèn)標(biāo)題即可,這個(gè)簡(jiǎn)單的函數(shù)可以抽象在項(xiàng)目工具函數(shù)里,每個(gè)頁(yè)面組件都需要調(diào)用。
function useDocumentTitle(title) { useEffect( () => { document.title = title; return () => (document.title = "前端精讀"); }, [title] ); }
在線 Demo
監(jiān)聽(tīng)頁(yè)面大小變化,網(wǎng)絡(luò)是否斷開(kāi)效果:在組件調(diào)用 useWindowSize 時(shí),可以拿到頁(yè)面大小,并且在瀏覽器縮放時(shí)自動(dòng)觸發(fā)組件更新。
const windowSize = useWindowSize(); return頁(yè)面高度:{windowSize.innerWidth};
實(shí)現(xiàn):和標(biāo)題思路基本一致,這次從 window.innerHeight 等 API 直接拿到頁(yè)面寬高即可,注意此時(shí)可以用 window.addEventListener("resize") 監(jiān)聽(tīng)頁(yè)面大小變化,此時(shí)調(diào)用 setValue 將會(huì)觸發(fā)調(diào)用自身的 UI 組件 rerender,就是這么簡(jiǎn)單!
最后注意在銷(xiāo)毀時(shí),removeEventListener 注銷(xiāo)監(jiān)聽(tīng)。
function getSize() { return { innerHeight: window.innerHeight, innerWidth: window.innerWidth, outerHeight: window.outerHeight, outerWidth: window.outerWidth }; } function useWindowSize() { let [windowSize, setWindowSize] = useState(getSize()); function handleResize() { setWindowSize(getSize()); } useEffect(() => { window.addEventListener("resize", handleResize); return () => { window.removeEventListener("resize", handleResize); }; }, []); return windowSize; }
在線 Demo
動(dòng)態(tài)注入 css效果:在頁(yè)面注入一段 class,并且當(dāng)組件銷(xiāo)毀時(shí),移除這個(gè) class。
const className = useCss({ color: "red" }); returnText.;
實(shí)現(xiàn):可以看到,Hooks 方便的地方是在組件銷(xiāo)毀時(shí)移除副作用,所以我們可以安心的利用 Hooks 做一些副作用。注入 css 自然不必說(shuō)了,而銷(xiāo)毀 css 只要找到注入的那段引用進(jìn)行銷(xiāo)毀即可,具體可以看這個(gè) 代碼片段。
DOM 副作用修改 / 監(jiān)聽(tīng)場(chǎng)景有一些現(xiàn)成的庫(kù)了,從名字上就能看出來(lái)用法:document-visibility、network-status、online-status、window-scroll-position、window-size、document-title。組件輔助
Hooks 還可以增強(qiáng)組件能力,比如拿到并監(jiān)聽(tīng)組件運(yùn)行時(shí)寬高等。
獲取組件寬高效果:通過(guò)調(diào)用 useComponentSize 拿到某個(gè)組件 ref 實(shí)例的寬高,并且在寬高變化時(shí),rerender 并拿到最新的寬高。
const ref = useRef(null); let componentSize = useComponentSize(ref); return ( <> {componentSize.width}