React Custom Hooks 最佳实践
brickspert opened this issue · 7 comments
组件
组件是 UI + 逻辑的复用,但逻辑复用能力等于 0。
一个 React 项目,是由无数个大大小小的组件组合而成的。在 React 的世界中,组件是一等公民。而我们平时拆分组件的依据无非是:尽量的复用代码。
组件是 UI + 逻辑的复用,你不能将 UI 和逻辑拆开。比如 Antd 的 Cascader 级联选择 组件,内置了样式和级联选择的逻辑,用户使用的时候相当于一个黑盒,只管用就行了。但是有一个很现实的问题,当该组件的样式不能满足我们需求的时候,我们需要从 0 重新实现一个组件,重写 UI + 逻辑,哪怕逻辑真的一模一样。组件的逻辑复用能力等于 0。我可以想到一个可怕的事实,社区上的同类组件,大部分的逻辑都是可以复用的,只是在样式上有差异,但逻辑共享在社区上并没有很流行。
HOC 与 Render Props
HOC 与 Render Props 可以把逻辑抽出来复用,但并没有让逻辑复用流行起来。
当然,我上面说的不能复用有点夸张,React 提供了 HOC 与 Render Props 两种方式来解决逻辑复用的问题。比如下面的监听鼠标位置的逻辑,我们就可以通过 Render Props 来复用。
<Mouse>
(position)=> <OurComponent />
</Mouse>
同类逻辑包括监听 window size,监听 scroll 位置等等。但是我们一般很少用 render props 来封装逻辑,更少去和其它项目去共享逻辑。为什么呢?想想多个逻辑复用会怎么样,你就知道多可怕了。
<WindowSize>
(size)=> (
<Mouse>
(position)=> <OurComponent size={size} mouse={position}/>
</Mouse>
)
</WindowSize>
嵌套地狱的代码是我们不能忍受的,同时 HOC 也存在类似的问题,这可能是导致逻辑复用不能流行起来的一个重要原因。
React Hooks
React Hooks 很好的解决了逻辑复用的问题,同时社区中诞生了一批比较好的 React Hooks 库。
React Hooks 是今年 React 的一个重磅炸弹,在社区引起了激烈的回响。随着 Hooks 的诞生,我们可以通过 Custom Hooks 很方便的封装逻辑,逻辑共享也成为了潮流。比如上面的例子,我们就可以通过 react-use 很方便的实现。
import {useMouse, useWindowSize, useScroll} from 'react-use'
function Demo(){
const mousePosition = useMouse();
const windowSize = useWindowSize();
}
react-use 是社区中比较优秀的 Hooks 库,封装了很多常用的基础逻辑,在日常开发中必不可少。但是只用 react-use 就够了吗?显然不是。react-use 中的 Hooks 粒度比较小,类似于工具库。而在中台产品中,有很多特定的场景逻辑,需要多个 Hooks 进行组合,或者定制特定的逻辑。基于此,我们创建了 @umijs/hooks ,定位为为中台场景服务的 Hooks 库。
@umijs/hooks
@umijs/hooks 是面向中台应用场景的 Hooks 库,封装了中台常见场景的逻辑,让中台开发变得超级简单。@umijs/hooks 已经在蚂蚁金服多个产品中落地,口碑很好,提效明显。当然,你可能不信,口说无凭,那就用例子来说话。
useAntdTable
中台开发中,table 页面应该算最多的一个了,我们一般会使用 Antd 的 Table 组件来搭建,但是其中还是有很多逻辑,我们是无法避免的。
- 分页管理
- pageSize管理
- 分页变化,pageSize 变化时重新进行异步请求
- 筛选条件变化时,重置分页,并重新请求数据
- 异步请求的 loading 处理
- 异步请求的竞态处理
- 组件卸载时丢弃进行中的异步请求(很多人通常不处理,在某些情况会报警告)
上面的逻辑,我们在几乎所有的 table 页是必须要处理的,想想都可怕。useAntdTable 至少封装了上面 7 个逻辑,列表页开发从未变得如此简单。
const { table } = useAntdTable(asyncFn);
const columns = [];
return (
<Table columns={columns} rowKey="id" {...table} />
)
useSearch
常见的异步搜索场景,我们一般要集成:
- 防抖
- 异步请求的 loading 处理
- 异步请求的请求时序控制
- 组件卸载时取消防抖及异步请求等逻辑
现在一切变得如此简单:
const { data, loading, onChange } = useSearch(asyncFn);
<Select
onSearch={onChange}
loading={loading}
>
{data.map((item)=><Option />)}
</Select>
更多的 Custom Hooks
当然,我们还有更多极大提效的 CustomHooks,你能想象不用写一行逻辑,就能实现异步 loadmore 功能吗?
你能想象不用写一行逻辑,就能实现动态增删,排序的表单吗?
各种常见场景,通通不用写逻辑,通通不用写逻辑。
写在最后
umi hooks 让中台开发变得如此简单,我能想象,不久的将来,中台开发可以不用写一行逻辑,这也是我们为之奋斗的目标。
同时,我也知道,大家平时工作中也积累了很多常用的 Hooks,我们非常希望大家能参与进来,共建 umi hooks,无论对我们,还是用户,都是最好的福音。
❤️感谢大家
关注公众号「前端技术砖家」,拉你进交流群,大家一起共同交流和进步。
antd 重度用户,也在思考 antd 的组件逻辑的封装,先试用一下 umi hooks
对antd的版本有要求吧
对antd的版本有要求吧
只有 useAntdTable,这一个是和 antd 耦合的,其他的都和 antd 没关系。 并且对 antd 的版本没要求的。
useAntdTable 4.0 新的 Table 和 Form 的用法我们这边也看过了,现在内部项目里已经有
antd4.0 Table + useAntdTable
和 antd4.0 Form + useDynamicList
落地的场景了。作为纯粹逻辑的封装,对 antd 版本的依赖性不大,后面如果有使用差异我们也会第一时间补充上文档。
大哥有没有微信交流群呀
期待umi的发展
对antd的版本有要求吧
只有 useAntdTable,这一个是和 antd 耦合的,其他的都和 antd 没关系。 并且对 antd 的版本没要求的。
其实我理解的是,hooks和任何ui层面上的东西都没有耦合,因为hooks暴露的是能力(接口),任何ui组件只要实现了这个接口就可以使用.