ahooks 是阿里出的 React Hooks 工具库。ahooks 基于 React Hooks 的逻辑封装能力,提供了大量常见好用的 Hooks,可以极大的降低代码复杂度,提升开发效率。
场景1: 使用布尔值
我们用布尔值来控制弹出框的显示和隐藏,常会写这样的代码:
const [visible, setVisible] = useState(false)
const show = useCallback(() => {
setVisible(true)
}, [])
const hide = useCallback(() => {
setVisible(false)
}, [])
const toggle = useCallback(() => {
setVisible(v => !v)
}, [])
用 useBoolean
可以简化为:
const [
visible,
{setTrue: show, setFalse: hide, toggle, toggle}
] = useBoolean(false)
类似的,在两个值之间切换,可以用 useToggle
。下面的例子,展示了值在 Hello
和 World
之间切换:
const [state, { toggle }] = useToggle('Hello', 'World')
场景2: 将数据同步到 Web Storage
有时,在设置数据的时,将数据同步到 web Storage
。用 useLocalStorageState
可以将数据同步到 localStorage
。如:
const [message, setMessage] = useLocalStorageState('message', 'Hello~')
useEffect(() => {
// 依次 log:Hello~ null。'xxx' 'xxx'。
console.log(message, localStorage.getItem('message'))
}, [message])
useEffect(() => {
setTimeout(() => {
setMessage('xxx')
}, 1000)
}, [])
类似的,将数据同步用 sessionStorage
可以用 useSessionStorageState
。同步到 url
的请求参数中 可以用 useUrlState
。同步到 Cookie
用 useCookieState
。
场景3: 避免组件卸载后改组件状态,导致内存泄露
异步操作结束后更改组件状态,如果组件已被卸载,会导致内存泄露。为避免这种情况,我们一般用一个布尔值来存组件有没有被卸载,只有组件未卸载时,才改组件状态:
const [isUnmount, {setTrue, setFalse}] = useBoolean(false)
const [data, setData] = useState(null)
useEffect(() => {
setFalse()
fetchUser().then(({data}) => {
if(!isUnmount) {
setData(data)
}
})
return () => setTrue()
}, [])
用 useUnmountedRef
,可以简化为:
const unmountRef = useUnmountedRef()
const [data, setData] = useState(null)
useEffect(() => {
fetchUser().then(({data}) => {
if(!unmountRef.current) {
setData(data)
}
})
}, [])
也可以用 useSafeState
。它与 useState
完全一样,但是在组件卸载后 setState
不会被执行。如:
const [data, setData] = useSafeState(null)
useEffect(() => {
fetchUser().then(({data}) => {
setData(data)
})
return () => setTrue()
}, [])
场景4: 组件卸载前,需要做清理操作的封装
一些操作,在组件卸载时,需要做清理操作来防止内存泄露。如清除计时器,解绑事件绑定等。ahooks 对这些操作都有封装,来减少清除代码。计时器:
useTimeout(() => {
}, 1000)
useInterval(() => {
}, 1000)
事件绑定:
useEventListener('click', clickHandler, { target: ref })
return (
<button ref={ref} type="button">点我</button>
)
场景5: 获取事件数据
ahooks 封装了些获取常见事件数据的 hooks。
获得滚动事件的滚动位置:
const ref = useRef(null)
// scroll 对象上有 left,top 的属性值。
const scroll = useScroll(ref)
return (<div ref={ref}>...</div>)
获取元素的实时大小:
const ref = useRef(null)
// size 对象上有 width,height 的属性值。
const size = useSize(ref)
return (<div ref={ref}>...</div>)
获取鼠标的位置:
// mouse 对象上有鼠标的 clientX,clientY 等属性值。
const mouse = useMouse()
场景6: 防抖和节流
ahoos 中也有防抖和节流的 hooks。 防抖这么写:
const { run } = useDebounceFn(
() => setValue(value + 1),
{
wait: 500,
}
)
节流这么写:
const { run } = useThrottleFn(
() => setValue(value + 1),
{
wait: 500,
}
)
用 useDebounce 和 useThrottle 可以做到类似的效果。
场景7: 异步控制 & 调用接口
useRequest
是强大的管理异步数据 hook。支持:
- 自动请求/手动请求接口
- 请求的缓存/预加载
- 请求的防抖和节流
- 分页
- 集成请求库
- 等等
下面是自动请求的代码:
const { data, loading, error} = useRequest('/api/pets')
return (
<>
{!loading && !error && (
<div>渲染列表数据</div>
)}
{loading && (
<div>Loading...</div>
)}
{error && (
<div>加载出错</div>
)}
</div>
)
建议通读下官方文档。
场景8: 排查什么导致了组件重新渲染
我们可以通过避免复杂组件的不必要的重新渲染来提升组件性能。 用 useWhyDidYouUpdate
可以知道是哪个状态或属性的变化导致了组件的重新渲染。如:
useWhyDidYouUpdate(
'useWhyDidYouUpdateComponent',
{
...props,
state1,
state2,
// 更多可能会导致组件重新渲染的属性
}
)
更多
ahooks 还有好多好多 hooks:虚拟列表,拖拽,表格等等。没试过的朋友,赶紧试试吧~