序言
摘要
本文将介绍开源库ahook
中部分常用的API的底层实现原理。
介绍的方式是,提出应用场景和用法作为需求,然后希望读者先思考如何实现,再看源码验证答案。
另外,为了代码更加直观易懂,会尽可能省略不必要的TS等内容。
多余的话
很久没有写技术博客了。
据上一次写技术笔记,已经过去了将近一年了,这一年里,我获得了前所未有的成长,见到了不可思议的技术,还有超凡入圣的技术大师。
我的经历大概是这样的,说实话做到这一步我感觉非常满意了,真的,对我而言非常不容易:
LEC团队 (2020.10-2022.4)
教授的硬件设备公司 (2022.4-2022.5)
字节跳动-互娱研发(抖音) (2022.6-2022.10)
字节跳动-懂车帝 (2023.1-2023.5)
阿里巴巴-淘天集团 (2023.6-至今)
但就算如此,我也总是在耳畔听到一个声音:
“就这样而已吗?”
我想要成为JS Master,我不想止步于此,总有一天——十年也好,二十年也好,我一定要实现我的梦想。
综合业务实用性和技术成长性两个方面考虑,我决定从React的Hook封装开始深挖,通过学习AHook这个前人铸造的丰碑获得成长。
特别鸣谢
感谢阿里巴巴的开源库ahook
: https://github.com/alibaba/hooks。
这一年非常感谢心圆、洋仔、鸡哥等开源大佬对我在技术上的激励。
State
我们从状态相关的库开始学习。
useLatest
介绍
总是返回当前最新值的 Hook!可以避免闭包问题!
还是不太清楚具体是干什么的?那来看看下面这个场景:
export default App() {
const [cnt, setCnt] = useState(0)
useEffect(() => {
setInterval(() => {
setCnt(cnt + 1)
}, 400)
}, [])
return (
<div>
<div>cnt: {cnt}</div>
</div>
)
};
这里渲染的cnt
最终会卡在1。
我个人的理解是函数组件内的定时器把回调递出去挂到了计时线程上,内存泄漏形成了闭包,这时候的
cnt
还是0——由于只有首次渲染的时候才会设置定时器,所以之后每次触发都是获取到值为0的cnt
,也就导致渲染的结果卡在1。
这时,我们就可以使用useLatest
。
实现
useToggle
介绍
实现一个用于在两个状态值间切换的 Hook!
乍一听非常简单,但是需要注意,这可没说一定是布尔值。
让我们先给出一些基本的代码这样更容易理解我们要做些什么:
import { useState } from 'react'
// 注意,两个参数都是可选的
interface UseToggleProps {
leftValue?: any,
rightValue?: any,
}
const useToggle = (leftValue, rightValue) => {
const [state, setState] = useState(leftValue)
const action = useMemo(() => {
// ... TODO: 在这里补全代码
return {
set, // 设置 state
toggle, // 反转 state
setLeft, // 设置state为 leftValue
setRight, // 设置state为 rightValue ?? !leftValue
}
}, [])
return [state, setState];
}
实现
也就是实现四个函数, 让我们从简单的开始由上往下进行实现:
const useToggle = (leftValue, rightValue) => {
const [state, setState] = useState(leftValue)
const action: Action = useMemo(() => {
// --- 下面是补全的代码 ---
const set = (v) => { setState(v) }
const setLeft = () => { setState(leftValue) }
// 由于rightValue参数可选,所以并不一定存在右值,需要我们自行对左值取反
const revLeftValue = rightValue === undefined ? !leftValue : rightValue
const setRight = () => { setState(rightValue) }
const toggle = () => {
const newValue = state === leftValue ? revLeftValue : leftValue
setState(newValue)
}
// --- 上面是补全的代码 ---
return {
setLeft,
setRight,
set,
toggle,
}
}, [])
return [state, setState];
}
实际上也并不难对吧——甚至有些简单?
useDebounce
经典的防抖处理——就像是电梯门按钮一样,一直按就一直不关门,不按了过一会儿就关上了。