ahooks 是阿里出的 React Hooks 工具库。ahooks 基于 React Hooks 的逻辑封装能力,提供了大量常见好用的 Hooks,可以极大的降低代码复杂度,提升开发效率。

场景1: 使用布尔值

我们用布尔值来控制弹出框的显示和隐藏,常会写这样的代码:

  1. const [visible, setVisible] = useState(false)
  2. const show = useCallback(() => {
  3. setVisible(true)
  4. }, [])
  5. const hide = useCallback(() => {
  6. setVisible(false)
  7. }, [])
  8. const toggle = useCallback(() => {
  9. setVisible(v => !v)
  10. }, [])

useBoolean 可以简化为:

  1. const [
  2. visible,
  3. {setTrue: show, setFalse: hide, toggle, toggle}
  4. ] = useBoolean(false)

类似的,在两个值之间切换,可以用 useToggle。下面的例子,展示了值在 HelloWorld 之间切换:

  1. const [state, { toggle }] = useToggle('Hello', 'World')

场景2: 将数据同步到 Web Storage

有时,在设置数据的时,将数据同步到 web Storage。用 useLocalStorageState 可以将数据同步到 localStorage。如:

  1. const [message, setMessage] = useLocalStorageState('message', 'Hello~')
  2. useEffect(() => {
  3. // 依次 log:Hello~ null。'xxx' 'xxx'。
  4. console.log(message, localStorage.getItem('message'))
  5. }, [message])
  6. useEffect(() => {
  7. setTimeout(() => {
  8. setMessage('xxx')
  9. }, 1000)
  10. }, [])

类似的,将数据同步用 sessionStorage 可以用 useSessionStorageState。同步到 url 的请求参数中 可以用 useUrlState。同步到 CookieuseCookieState

场景3: 避免组件卸载后改组件状态,导致内存泄露

异步操作结束后更改组件状态,如果组件已被卸载,会导致内存泄露。为避免这种情况,我们一般用一个布尔值来存组件有没有被卸载,只有组件未卸载时,才改组件状态:

  1. const [isUnmount, {setTrue, setFalse}] = useBoolean(false)
  2. const [data, setData] = useState(null)
  3. useEffect(() => {
  4. setFalse()
  5. fetchUser().then(({data}) => {
  6. if(!isUnmount) {
  7. setData(data)
  8. }
  9. })
  10. return () => setTrue()
  11. }, [])

useUnmountedRef,可以简化为:

  1. const unmountRef = useUnmountedRef()
  2. const [data, setData] = useState(null)
  3. useEffect(() => {
  4. fetchUser().then(({data}) => {
  5. if(!unmountRef.current) {
  6. setData(data)
  7. }
  8. })
  9. }, [])

也可以用 useSafeState。它与 useState 完全一样,但是在组件卸载后 setState 不会被执行。如:

  1. const [data, setData] = useSafeState(null)
  2. useEffect(() => {
  3. fetchUser().then(({data}) => {
  4. setData(data)
  5. })
  6. return () => setTrue()
  7. }, [])

场景4: 组件卸载前,需要做清理操作的封装

一些操作,在组件卸载时,需要做清理操作来防止内存泄露。如清除计时器,解绑事件绑定等。ahooks 对这些操作都有封装,来减少清除代码。计时器:

  1. useTimeout(() => {
  2. }, 1000)
  3. useInterval(() => {
  4. }, 1000)

事件绑定:

  1. useEventListener('click', clickHandler, { target: ref })
  2. return (
  3. <button ref={ref} type="button">点我</button>
  4. )

场景5: 获取事件数据

ahooks 封装了些获取常见事件数据的 hooks。

获得滚动事件的滚动位置:

  1. const ref = useRef(null)
  2. // scroll 对象上有 left,top 的属性值。
  3. const scroll = useScroll(ref)
  4. return (<div ref={ref}>...</div>)

获取元素的实时大小:

  1. const ref = useRef(null)
  2. // size 对象上有 width,height 的属性值。
  3. const size = useSize(ref)
  4. return (<div ref={ref}>...</div>)

获取鼠标的位置:

  1. // mouse 对象上有鼠标的 clientX,clientY 等属性值。
  2. const mouse = useMouse()

场景6: 防抖和节流

ahoos 中也有防抖和节流的 hooks。 防抖这么写:

  1. const { run } = useDebounceFn(
  2. () => setValue(value + 1),
  3. {
  4. wait: 500,
  5. }
  6. )

节流这么写:

  1. const { run } = useThrottleFn(
  2. () => setValue(value + 1),
  3. {
  4. wait: 500,
  5. }
  6. )

useDebounceuseThrottle 可以做到类似的效果。

场景7: 异步控制 & 调用接口

useRequest 是强大的管理异步数据 hook。支持:

  • 自动请求/手动请求接口
  • 请求的缓存/预加载
  • 请求的防抖和节流
  • 分页
  • 集成请求库
  • 等等

下面是自动请求的代码:

  1. const { data, loading, error} = useRequest('/api/pets')
  2. return (
  3. <>
  4. {!loading && !error && (
  5. <div>渲染列表数据</div>
  6. )}
  7. {loading && (
  8. <div>Loading...</div>
  9. )}
  10. {error && (
  11. <div>加载出错</div>
  12. )}
  13. </div>
  14. )

建议通读下官方文档

场景8: 排查什么导致了组件重新渲染

我们可以通过避免复杂组件的不必要的重新渲染来提升组件性能。 用 useWhyDidYouUpdate 可以知道是哪个状态或属性的变化导致了组件的重新渲染。如:

  1. useWhyDidYouUpdate(
  2. 'useWhyDidYouUpdateComponent',
  3. {
  4. ...props,
  5. state1,
  6. state2,
  7. // 更多可能会导致组件重新渲染的属性
  8. }
  9. )

更多

ahooks 还有好多好多 hooks:虚拟列表,拖拽,表格等等。没试过的朋友,赶紧试试吧~

推荐阅读