- 前言
大家好,我是若川。我倾力持续组织了一年多每周大家一起学习200行左右的源码共读活动,感兴趣的可以点此扫码加我微信 ruochuan02
参与。另外,想学源码,极力推荐关注我写的专栏《学习源码整体架构系列》,目前是掘金关注人数(4.7k+人)第一的专栏,写有20余篇源码文章。
最近 React
出了 新文档 react.dev,新中文文档 zh-hans.react.dev。
现在用 react
开发离不开各种 hooks
。学习各种 hooks
的工具库,有助于我们更好的使用和理解 hooks
。前端社区中有活跃的 ahooks。不过,这次我们来学习目前 36.2k
star
的 react-use 库。
react-use 文档
是用 storybook 搭建的。
如果公司项目需要搭建组件库或者 hooks
、工具库等,storybook 或许是不错的选择。
react-use 中文翻译仓库,最后更新是2年前,可能有点老。
- 环境准备
看一个开源仓库,第一步一般是看 README.md
和 contributing.md
贡献文档。第二步的克隆下来。按照贡献指南文档,把项目跑起来。
贡献文档中有如下文档。
2.1 创建一个新 hook 的步骤
- 创建
src/useYourHookName.ts
和stories/useYourHookName.story.tsx
,然后运行yarn start
。 - 创建
tests/useYourHookName.test.ts
,运行yarn test:watch
监听测试用例执行。 - 创建
docs/useYourHookName.md
文档。 - 在
src/index.ts
文件导出你写的hook
,然后添加你的hook
到REAMDE.md
中。
我们可以得知具体要做什么,新增 hook
关联哪些文件。
1 | shell复制代码# 推荐克隆我的仓库 |
克隆项目到本地,安装依赖完成后,执行 yarn start
。
本地环境打开 useEffectOnce
docs
:http://localhost:6008/?path=/story/lifecycle-useeffectonce--docs
我们先挑选这个 useEffectOnce
简单的 hook
来分析。
2.2 useEffectOnce
2.2.1 react-use/src/useEffectOnce.ts
1 | ts复制代码// react-use/src/useEffectOnce.ts |
我们来看测试用例,直接使用测试用例调试 useEffectOnce
源码。
我之前写过相关文章。可以参考学习。
你可能不知道测试用例(Vitest)可以调试开源项目(Vue3) 源码
我装了 jest
和 jest runner
vscode
插件,装完后测试用例中会直接显示 run
、和 debug
按钮。还在装了 vitest
、vitest runner
vscode
插件,装完后测试用例中会直接显示 run(vitest)
和 debug(vitest)
按钮。
如下图所示。
这个项目使用的是 jest
。于是我点击最右侧的 debug
。
2.2.2 react-use/tests/useEffectOnce.test.ts
1 | ts复制代码// react-use/tests/useEffectOnce.test.ts |
2.2.3 react-use/stories/useEffectOnce.story.tsx
xxx.story.tsx
渲染组件,可以直接操作。Demo
和 docs
。
1 | ts复制代码// react-use/stories/useEffectOnce.story.tsx |
docs/useEffectOnce.md
省略,基本跟测试用例一样。可以说测试用例就是活文档。
接下来我们来看其他的 hooks
源码,限于篇幅,主要就讲述源码,不包含测试用例、文档、story
。
TS
也不会过多描述。如果对TS不太熟悉,推荐学习这个《TypeScript 入门教程》。
我们先来看 Sensors
行为部分。
- Sensors 行为
3.1 useIdle
tracks whether user is being inactive.
跟踪用户是否处于非活动状态。
主要是:监听用户行为的事件(默认的 'mousemove', 'mousedown', 'resize', 'keydown', 'touchstart', 'wheel'
),指定时间内没有用户操作行为就是非活动状态。
1 | js复制代码import { useEffect, useState } from 'react'; |
我们接着来看,useLocation
hook
。
3.2 useLocation
useLocation docs |
useLocation demo
React sensor hook that tracks brower’s location.
主要获取 window.location
等对象信息。
阮一峰老师的网道:history
阮一峰老师的网道:location
自定义事件 mdn 创建和触发 events
1 | ts复制代码import { useEffect, useState } from 'react'; |
接着我们继续来看 State
状态部分。
- State 状态
4.1 useFirstMountState
useFirstMountState docs | useFirstMountState demo
Returns true if component is just mounted (on first render) and false otherwise.
若组件刚刚加载(在第一次渲染时),则返回true
,否则返回false
。
1 | ts复制代码import { useRef } from 'react'; |
4.2 usePrevious
usePrevious docs |
usePrevious demo
React state hook that returns the previous state as described in the React hooks FAQ.
保留上一次的状态。
利用 useRef
的不变性。
1 | ts复制代码import { useEffect, useRef } from 'react'; |
4.3 useSet
React state hook that tracks a Set.
new Set
的 hooks 用法。
useSet 可以用来列表展开、收起等其他场景。
返回 [set ,{add, remove, toggle, reset, has }]
1 | ts复制代码import { useCallback, useMemo, useState } from 'react'; |
4.4 useToggle
useToggle docs |
useToggle demo
tracks state of a boolean.
跟踪布尔值的状态。
切换 false => true => false
1 | ts复制代码import { Reducer, useReducer } from 'react'; |
我们继续来看 Side-effects
副作用部分。
- Side-effects 副作用
5.1 useMountedState
useMountedState
属于 lifecycle
模块,但这个 hook
在 useAsyncFn
中使用,所以放到这里讲述。
useMountedState docs |
useMountedState demo
NOTE!: despite having State in its name this hook does not cause component re-render. This component designed to be used to avoid state updates on unmounted components.
注意!:尽管名称中有State,但该钩子不会导致组件重新呈现。此组件设计用于避免对未安装的组件进行状态更新。
Lifecycle hook providing ability to check component’s mount state.
Returns a function that will return true if component mounted and false otherwise.
生命周期挂钩提供了检查组件装载状态的能力。
返回一个函数,如果组件已安装,则返回true,否则返回false。
1 | ts复制代码import { useCallback, useEffect, useRef } from 'react'; |
5.2 useAsyncFn
useAsyncFn docs |
useAsyncFn demo
React hook that returns state and a callback for an async function or a function that returns a promise. The state is of the same shape as useAsync.
为异步函数或返回promise的函数返回状态和回调的React钩子。状态与useAsync的形状相同。
看了 useMountedState
hook
,我们继续看 useAsyncFn
函数源码。
主要函数传入 Promise
函数 fn
,然后执行函数 fn.then()。
返回 state、callback(fn.then)。
1 | ts复制代码// 省略若干代码 |
5.3 useAsync
React hook that resolves an async function or a function that returns a promise;
解析异步函数或返回promise
的函数的React
钩子;
1 | ts复制代码import { DependencyList, useEffect } from 'react'; |
5.4 useAsyncRetry
useAsyncRetry docs |
useAsyncRetry demo
Uses useAsync with an additional retry method to easily retry/refresh the async function;
重试
主要就是变更依赖,次数(attempt),变更时会执行 useAsync
的 fn
函数。
1 | ts复制代码import { DependencyList, useCallback, useState } from 'react'; |
5.5 useTimeoutFn
useTimeoutFn
属于 Animations
模块,但这个 hook
在 useDebounce
中使用,所以放到这里讲述。
useTimeoutFn docs | useTimeoutFn demo
Calls given function after specified amount of milliseconds.
在指定的毫秒数后调用给定的函数。
主要是 useRef
和 setTimeout
结合实现的。
1 | ts复制代码import { useCallback, useEffect, useRef } from 'react'; |
5.6 useDebounce
useDebounce docs |
useDebounce demo
React hook that delays invoking a function until after wait milliseconds have elapsed since the last time the debounced function was invoked.
防抖
1 | ts复制代码import { DependencyList, useEffect } from 'react'; |
5.7 useThrottle
useThrottle docs |
useThrottle demo
React hooks that throttle.
节流
1 | ts复制代码import { useEffect, useRef, useState } from 'react'; |
我们继续来看 UI
用户界面部分。
- UI 用户界面
6.1 useFullscreen
useFullscreen docs |
useFullscreen demo
Display an element full-screen, optional fallback for fullscreen video on iOS.
实现全屏
主要使用 screenfull npm 包实现。
1 | ts复制代码import { RefObject, useState } from 'react'; |
我们继续来看 Lifecycles
生命周期部分。
- Lifecycles 生命周期
7.1 useLifecycles
useLifecycles docs |
useLifecycles demo
React lifecycle hook that call mount and unmount callbacks, when component is mounted and un-mounted, respectively.
React 生命周期挂钩,分别在组件安装和卸载时调用。
1 | ts复制代码import { useEffect } from 'react'; |
7.2 useCustomCompareEffect
useCustomCompareEffect docs |
useCustomCompareEffect demo
A modified useEffect hook that accepts a comparator which is used for comparison on dependencies instead of reference equality.
一个经过修改的useEffect钩子,它接受一个比较器,该比较器用于对依赖项进行比较,而不是对引用相等进行比较。
1 | ts复制代码import { DependencyList, EffectCallback, useEffect, useRef } from 'react'; |
7.3 useDeepCompareEffect
useDeepCompareEffect docs |
useDeepCompareEffect demo
A modified useEffect hook that is using deep comparison on its dependencies instead of reference equality.
一个修改后的useEffect
钩子,它对其依赖项使用深度比较,而不是引用相等。
1 | ts复制代码import { DependencyList, EffectCallback } from 'react'; |
最后,我们来看 Animations
生命周期部分。
- Animations 动画
8.1 useUpdate
useUpdate docs |
useUpdate demo
React utility hook that returns a function that forces component to re-render when called.
React 实用程序钩子返回一个函数,该函数在调用时强制组件重新渲染。
主要用了 useReducer
每次调用 updateReducer
方法,来达到强制组件重新渲染的目的。
1 | js复制代码import { useReducer } from 'react'; |
- 总结
行文至此,我们简单分析了若干 react-use 的自定义 React Hooks
。想进一步学习的小伙伴,可以继续学完剩余的 hooks
。还可以学习 ahooks、别人写的 ahooks 源码分析、
beautiful-react-hooks、mantine-hooks 等。
学习过程中带着问题多查阅 React
新文档 react.dev,新中文文档 zh-hans.react.dev,相信收获更大。
如果技术栈是 Vue
,感兴趣的小伙伴可以学习 VueUse。
如果能看完一些 React Hooks 工具集合库的源码。相信一定能对 React Hooks
有更深的理解,自己写自定义 React Hooks
时也会更加顺利、快速。
如果看完有收获,欢迎点赞、评论、分享支持。你的支持和肯定,是我写作的动力。
最后可以持续关注我@若川。另外,想学源码,极力推荐关注我写的专栏《学习源码整体架构系列》,目前是掘金关注人数(4.7k+人)第一的专栏,写有20余篇源码文章。
我倾力持续组织了一年多每周大家一起学习200行左右的源码共读活动,感兴趣的可以点此扫码加我微信 ruochuan02
参与。
本文正在参加「金石计划」
本文转载自: 掘金