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:虚拟列表,拖拽,表格等等。没试过的朋友,赶紧试试吧~
