## 1 引言 上周的 [精读《React Hooks》](https://github.com/dt-fe/weekly/blob/master/79.%E7%B2%BE%E8%AF%BB%E3%80%8AReact%20Hooks%E3%80%8B.md) 已经实现了对 React Hooks 的基本认知,也许你也看了 React Hooks 基本实现剖析(单向链表),但理解实现原理就可以用好了吗?学的是知识,而用的是技能,看别人的用法就像刷抖音一样(哇,饭还可以这样吃?),你总会有新的收获。 这篇文章将这些知识实践起来,看看广大程序劳动人民是如何发掘 React Hooks 的潜力的(造什么轮子)。 首先,站在使用角度,要理解 React Hooks 的特点是 “非常方便的 Connect 一切”,所以无论是数据流、Network,或者是定时器都可以监听,有一点 RXJS 的意味,也就是你可以利用 React Hooks,将 React 组件打造成:任何事物的变化都是输入源,当这些源变化时会重新触发 React 组件的 render,你只需要挑选组件绑定哪些数据源(use 哪些 Hooks),然后只管写 render 函数就行了! ## 2 精读 参考了部分 React Hooks 组件后,笔者按照功能进行了一些分类。 > 由于 React Hooks 并不是非常复杂,所以就不按照技术实现方式去分类了,毕竟技术总有一天会熟练,而且按照功能分类才有持久的参考价值。 ### DOM 副作用修改 / 监听 做一个网页,总有一些看上去和组件关系不大的麻烦事,比如修改页面标题(切换页面记得改成默认标题)、监听页面大小变化(组件销毁记得取消监听)、断网时提示(一层层装饰器要堆成小山了)。而 React Hooks 特别擅长做这些事,造这种轮子,大小皆宜。 > 由于 React Hooks 降低了高阶组件使用成本,那么一套生命周期才能完成的 “杂耍” 将变得非常简单。 下面举几个例子: #### 修改页面 title 效果:在组件里调用 `useDocumentTitle` 函数即可设置页面标题,且切换页面时,页面标题重置为默认标题 “前端精读”。 ```tsx useDocumentTitle("个人中心"); ``` 实现:直接用 `document.title` 赋值,不能再简单。在销毁时再次给一个默认标题即可,这个简单的函数可以抽象在项目工具函数里,每个页面组件都需要调用。 ```tsx function useDocumentTitle(title) { useEffect( () => { document.title = title; return () => (document.title = "前端精读"); }, [title] ); } ``` [在线 Demo](https://codesandbox.io/s/lrnvnx866l) #### 监听页面大小变化,网络是否断开 效果:在组件调用 `useWindowSize` 时,可以拿到页面大小,并且在浏览器缩放时自动触发组件更新。 ```tsx const windowSize = useWindowSize(); return
页面高度:{windowSize.innerWidth}
; ``` 实现:和标题思路基本一致,这次从 `window.innerHeight` 等 API 直接拿到页面宽高即可,注意此时可以用 `window.addEventListener('resize')` 监听页面大小变化,此时调用 `setValue` 将会触发调用自身的 UI 组件 rerender,就是这么简单! 最后注意在销毁时,`removeEventListener` 注销监听。 ```tsx 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](https://codesandbox.io/s/j2rz2mj83) #### 动态注入 css 效果:在页面注入一段 class,并且当组件销毁时,移除这个 class。 ```tsx const className = useCss({ color: "red" }); return
Text.
; ``` 实现:可以看到,Hooks 方便的地方是在组件销毁时移除副作用,所以我们可以安心的利用 Hooks 做一些副作用。注入 css 自然不必说了,而销毁 css 只要找到注入的那段引用进行销毁即可,具体可以看这个 [代码片段](https://github.com/streamich/nano-css/blob/c21413ddbed233777886f7c9aa1375af8a221f7b/addon/pipe.js#L51)。 > DOM 副作用修改 / 监听场景有一些现成的库了,从名字上就能看出来用法:[document-visibility](https://github.com/rehooks/document-visibility)、[network-status](https://github.com/rehooks/network-status)、[online-status](https://github.com/rehooks/online-status)、[window-scroll-position](https://github.com/rehooks/window-scroll-position)、[window-size](https://github.com/rehooks/window-size)、[document-title](https://github.com/rehooks/document-title)。 ### 组件辅助 Hooks 还可以增强组件能力,比如拿到并监听组件运行时宽高等。 #### 获取组件宽高 效果:通过调用 `useComponentSize` 拿到某个组件 ref 实例的宽高,并且在宽高变化时,rerender 并拿到最新的宽高。 ```tsx const ref = useRef(null); let componentSize = useComponentSize(ref); return ( <> {componentSize.width}