深入解读ahooks

简介: 本文适合对打造工具函数库感兴趣的小伙伴阅读。

一、前言


本文基于开源项目:

https://github.com/alibaba/hooks

https://ahooks.js.org/guide/

https://github.com/lerna/lerna

image.png

 

   广东靓仔在看ahooks项目代码的时候发现了一些有意思的东西,这里分享下。


二、ahooks是什么


   ahooks是一套高质量可靠的 React Hooks 库


具有以下特性:

  • 易学易用
  • 支持 SSR
  • 对输入输出函数做了特殊处理,且避免闭包问题
  • 包含大量提炼自业务的高级 Hooks
  • 包含丰富的基础 Hooks
  • 使用 TypeScript 构建,提供完整的类型定义文件

安装:

$ npm install --save ahooks
# or
$ yarn add ahooks


使用:

import { useRequest } from 'ahooks';


三、项目目录


广东靓仔把ahooks的项目代码目录截了个图,如下所示:

image.png


看到这个目录,有种亲切的感觉,经过粗略的查看,跟dumi脚手架有点相似,经过求证,确定是使用dumi搭建的。


目录讲解:

+-- config                 // 项目配置
+-- docs                   // 组件库文档目录  
|  +-- guide               // 组件库文档其他路由
|  +-- index.en-US.md      // 组件库文档首页(英文)
|  +-- index.zh-CN.md      // 组件库文档首页(中文)
+-- packages               // lerna包
|  +-- hooks               // 子包hooks
|  +-- use-url-state       // 子包use-url-state
+-- webpack.common.js      // webpack配置文件
+-- gulpfile.js            // 自动化构建工具配置
+-- lerna.json             // 把各个小功能拆分成独立的npm库


看到这里我们先来温习下dumi相关知识。


四、dumi


dumi是为组件开发场景而生的文档工具。

dumi经常与father搭配使用,father 负责构建,而 dumi 负责组件开发及组件文档生成。


安装使用:

$ npx @umijs/create-dumi-lib        # 初始化一个文档模式的组件库开发脚手架
# or
$ yarn create @umijs/dumi-lib
$ npx @umijs/create-dumi-lib --site # 初始化一个站点模式的组件库开发脚手架
# or
$ yarn create @umijs/dumi-lib --site


效果如下:

image.png

image.png


篇幅有限,这里稍微提下:

1、菜单目录,我们可以通过在config配置navs、menus

2、dumi配置中en-US 是默认语言,如果需要中文创建一个带 zh-CN locale 后缀的同名 Markdown 文件即可。


更多的dumi相关知识可以前往官方文档查看:

https://d.umijs.org/guide


五、hooks


回到ahooks中,从项目目录中可以看到hooks文件是整个工具库的核心


+-- hooks 
|  +-- src               // 子包hooks的源码目录
|  +-- gulpfile.js       // 自动化构建配置
|  +-- package.json      
|  +-- tsconfig.json     // ts配置
|  +-- webpack.config.js // webpack配置
|  +-- yarn.lock         // 锁定版本


在查看源代码的过程中,广东靓仔看到了lodash的影子,推荐一下lodash

下面我们来看看这个hooks具体内容。


tsconfig.json


{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "rootDir": "src"
  }
}


利用extends属性从根目录的tsconfig.json配置文件里继承配置。

compilerOptions指定src文件目录(用于输出),用于控制输出目录结构


webpack.config.js


const merge = require('webpack-merge');
const common = require('../../webpack.common.js');
const path = require('path');
module.exports = merge(common, {
  entry: './es/index.js', // 入口模块的文件相对路径
  output: { // 输出到的目录
    filename: 'ahooks.js',
    library: 'ahooks',
    path: path.resolve(__dirname, './dist'),
  },
});


 webpack.common.js 公共配置文件  -- 抽离出公共的部分  通过merge进行合并

代码裁剪下,方便理解:


module.exports = merge(common, config);


webpack.common.js


里面没有什么特殊的,打包的时候,ahooks不想把react打到bundle中,所以使用了如下配置:


externals: [
    {
      react: 'React',
    },
  ],


gulpfile.js


const commonConfig = require('../../gulpfile');
exports.default = commonConfig.default;


ahooks使用了gulp自动化构建工具增强工作流程


gulpfile配置

const gulp = require('gulp');
const babel = require('gulp-babel');
const ts = require('gulp-typescript');
const del = require('del');
gulp.task('clean', async function () {
 ...
});
gulp.task('cjs', function () {
   ...
});
gulp.task('es', function () {
   ...
});
gulp.task('declaration', function () {
  ...
});
gulp.task('copyReadme', async function () {
   ...
});
exports.default = gulp.series('clean', 'cjs', 'es', 'declaration', 'copyReadme');


可以看到使用了gulp的series()clean、cjs、es、declaration、copyReadme组合成更大的操作,然后依次执行


clean里面调用了del类似于rimraf删除当前工作目录


cjs使用gulp-typescript编译 TypeScript 文件流


declaration生成相应的 .d.ts 文件


copyReadme创建一个用于将 hooks文件的元数据对象写入到文件系统的流


lerna.json

ahooks使用了lerna集中了子包在同一个站点中。

Lerna 是一个工具,可以优化使用 git 和 npm 管理多包存储库的工作流程。

广东靓仔把package.json里面关于lerna剪切了下来,如下:


"scripts": {
    "bootstrap": "lerna bootstrap",
    "clean": "lerna clean --yes",
    "build": "lerna run build",
    "pub": "yarn run build && lerna publish",
    "pub:beta": "yarn run build && lerna publish --dist-tag beta"
  },


Lerna 中的两个主要命令是lerna bootstraplerna publish

bootstrap将 repo 中的依赖项链接在一起。publish将帮助发布任何更新的包。

ahooks的lerna配置如下:


{
  "version": "3.1.9",
  "packages": ["packages/*"],
  "npmClient": "yarn",
  "command": {
    "version": {
      "allowBranch": "master",
      "includeMergedTags": true
    },
    "publish": {
      "message": "chore(release): publish",
      "registry": "https://registry.npmjs.org/"
    }
  }
}


  • version:存储库的当前版本。
  • packages: 用作包位置的 glob 数组。
  • npmClient:用于指定特定客户端以运行命令的选项(也可以在每个命令的基础上指定)。更改为"yarn"使用 yarn 运行所有命令。默认为“npm”。
  • command.version.allowBranch: lerna version当从除master. 仅限制lerna version在主分支被认为是最佳实践
  • command.version.includeMergedTags: 检测到更改的包时包括来自合并分支的标签
  • command.publish.message:执行版本更新以进行发布时的自定义提交消息
  • command.publish.registry:使用它来设置要发布到的自定义注册表 url 而不是 npmjs.org,如果需要,您必须已经过身份验证。

六、工具函数


export {
  useRequest,
  useControllableValue,
  useDynamicList,
  useVirtualList,
  useResponsive,
  useEventEmitter,
  useLocalStorageState,
  useSessionStorageState,
  useSize,
  configResponsive,
  useUpdateEffect,
  useUpdateLayoutEffect,
  useBoolean,
  useToggle,
  useDocumentVisibility,
  useSelections,
  useThrottle,
  useThrottleFn,
  useThrottleEffect,
  useDebounce,
  useDebounceFn,
  useDebounceEffect,
  usePrevious,
  useMouse,
  useScroll,
  useClickAway,
  useFullscreen,
  useInViewport,
  useKeyPress,
  useEventListener,
  useHover,
  useUnmount,
  useSet,
  useMemoizedFn,
  useMap,
  useCreation,
  useDrag,
  useDrop,
  useMount,
  useCounter,
  useUpdate,
  useTextSelection,
  useEventTarget,
  useHistoryTravel,
  useCookieState,
  useSetState,
  useInterval,
  useWhyDidYouUpdate,
  useTitle,
  useNetwork,
  useTimeout,
  useReactive,
  useFavicon,
  useCountDown,
  useWebSocket,
  useLockFn,
  useUnmountedRef,
  useExternal,
  useSafeState,
  useLatest,
  useIsomorphicLayoutEffect,
  useDeepCompareEffect,
  useAsyncEffect,
  useLongPress,
  useRafState,
  useTrackedEffect,
  usePagination,
  useAntdTable,
  useFusionTable,
  useInfiniteScroll,
  useGetState,
  clearCache,
  useFocusWithin,
};


ahook写了以上工具函数,平时开发过程中自己用到的其实并没有这么多,我们可以封装自己的hooks。


七、总结


   在我们阅读完官方文档后,我们一定会进行更深层次的学习,比如看下框架底层是如何运行的,以及源码的阅读。    


这里广东靓仔给下一些小建议:

  • 在看源码前,我们先去官方文档复习下框架设计理念、源码分层设计
  • 阅读下框架官方开发人员写的相关文章
  • 借助框架的调用栈来进行源码的阅读,通过这个执行流程,我们就完整的对源码进行了一个初步的了解
  • 接下来再对源码执行过程中涉及的所有函数逻辑梳理一遍
相关文章
|
存储 前端开发 JavaScript
ahooks 正式发布:值得拥抱的 React Hooks 工具库
ahook定位于一套基于 React Hooks 的工具库,核心围绕 React Hooks 的逻辑封装能力,降低代码复杂度和避免团队的重复建设为背景,共同建设和维护阿里经济体层面的 React Hooks 库。
22384 1
ahooks 正式发布:值得拥抱的 React Hooks 工具库
|
缓存 前端开发 算法
【译】你真的应该使用useMemo吗? 让我们一起来看看
- 当处理量很大时,应该使用 useMemo - 从什么时候 useMemo 变得有用以避免额外处理,阈值在很大程度上取决于您的应用程序 - 数据在处理非常低的情况下使用 useMemo
1973 0
【已解决】Error: Element type is invalid: expected a string (for built-in components) or a class/function
Error: Element type is invalid: expected a string (for built-in components) or a class/function
2488 0
【已解决】Error: Element type is invalid: expected a string (for built-in components) or a class/function
|
前端开发 JavaScript API
ahooks 3.0 来了!高质量可靠的 React Hooks 库
ahooks 3.0 来了!高质量可靠的 React Hooks 库
688 0
|
11月前
|
存储 前端开发 C++
antd 实现批量上传
antd 实现批量上传
660 0
|
12月前
umi中@umijs/plugin-dva的使用,及实现一套增删改
符合以下规则的文件会被认为是 model 文件: • src/models 下的文件 • src/pages 下,子目录中 models 目录下的文件 • src/pages 下,所有model.ts 文件(不区分任何字母大小写)
304 0
|
存储 缓存 前端开发
React Query 完全指南,时下最热辣的请求库!
小伙伴们,是时候开始 React Query 之旅了。你还不知道这个库吗?完美,你来对地方了
|
存储 Web App开发 JSON
前端 i18n 最佳实践:在 React 中使用 i18next
前端 i18n 最佳实践:在 React 中使用 i18next
1672 0
|
缓存 移动开发 前端开发