在上一篇教程中,我们通过动画的方式不断深入 useState 和 useEffect,基本上理清了 React Hooks 背后的实现机制——链表,同时也实现了 COVID-19 数据可视化应用的全球数据总览和多个国家数据的直方图。
用动画和实战打开 React Hooks(一):useState 和 useEffectzhuanlan.zhihu.com如果你想直接从这一篇教程开始阅读和实践,可下载本教程的源码:
git clone -b second-part https://github.com/tuture-dev/covid-19-with-hooks.git
# 或者克隆 Gitee 的仓库
git clone -b second-part https://gitee.com/tuture/covid-19-with-hooks.git
在第二篇教程中,我们将手把手带你用自定义 Hook 重构之前的组件代码,让它变得更清晰、并且可以实现逻辑复用。在重构完成之后,我们陷入了组件“不断获取数据并重新渲染”的无限循环,这时候,useCallback 站了出来,如同定海神针一般拯救了我们的应用……
自定义 Hook:量身定制
自定义 Hook 是 React Hooks 中最有趣的功能,或者说特色。简单来说,它用一种高度灵活的方式,能够让你在不同的函数组件之间共享某些特定的逻辑。我们先来通过一个非常简单的例子来看一下。
一个简单的自定义 Hook
先来看一个 Hook,名为 useBodyScrollPosition
,用于获取当前浏览器的垂直滚动位置:
function useBodyScrollPosition() {
const [scrollPosition, setScrollPosition] = useState(null);
useEffect(() => {
const handleScroll = () => setScrollPosition(window.scrollY);
document.addEventListener('scroll', handleScroll);
return () =>
document.removeEventListener('scroll', handleScroll);
}, []);
return scrollPosition;
}
通过观察,我们可以发现自定义 Hook 具有以下特点:
- 表面上:一个命名格式为
useXXX
的函数,但不是 React 函数式组件 - 本质上:内部通过使用 React 自带的一些 Hook (例如
useState
和useEffect
)来实现某些通用的逻辑
如果你发散一下思维,可以想到有很多地方可以去做自定义 Hook:DOM 副作用修改/监听、动画、请求、表单操作、数据存储等等。
提示
这里推荐两个强大的 React Hooks 库:React Use 和 Umi Hooks。它们都实现了很多生产级别的自定义 Hook,非常值得学习。
我想这便是 React Hooks 最大的魅力——通过几个内置的 Hook,你可以按照某些约定进行任意组合,“制造出”任何你真正需要的 Hook,或者调用他人写好的 Hook,从而轻松应对各种复杂的业务场景。就好像大千世界无奇不有,却不过是由一百多种元素组合而成。
管窥自定义 Hook 背后的原理
又到了动画时间。我们来看看在组件初次渲染时的情形:
我们在 App
组件中调用了 useCustomHook
钩子。可以看到,即便我们切换到了自定义 Hook 中,Hook 链表的生成依旧没有改变。再来看看重渲染的情况:
同样地,即便代码的执行进入到自定义 Hook 中,我们依然可以从 Hook 链表中读取到相应的数据,这个”配对“的过程总能成功。