这是蚂蚁金服内部技术分享的文字稿,本次分享主要介绍了为何要用 Hooks?以及如何使用 Umi Hooks 提效?react
Umi Hooks github.com/umijs/hooksgit
你们好,我叫尽龙,来自体验技术部。社区名称叫 brickspert,砖家的意思。程序员
自从 React 推出 React Hooks 后,就开始尝试使用 Hooks,并逐渐喜欢上了它。目前,几乎 100% 的组件都是使用 Hooks 开发。通过大半年的实践,在 Hooks 使用方面沉淀了一些经验,很高兴今天有机会能分享给你们。github
在分享开始以前,我想了解下:“有多少同窗目前已经在项目中大量使用 Hooks 了?”面试
嗯嗯,谢谢。看举手的同窗,大概一半一半吧。不要紧,听完今天的分享,我相信你必定有兴趣尝试下 Hooks 的。redux
React Hooks 是 react v16.8 的一个新特性,很佩服这么重磅的功能,在一个小版本中发布,说明 React 团队有足够的信心向上兼容。c#
为何要放弃 Class,转用 Hooks 呢?在内部外部有不少争论,包括知乎也有相似提问。咱们也难免俗套的要对比下 Class 和 Hooks 了。固然为了保证今天的分享效果,我确定会偏向 Hooks 的(哈哈哈哈)。bash
Class 学习成本很高。首当其中的就是生命周期,多,太多了。不只多,还会变!React v15 和 v16 就不同。下面是我在网上随便找的一张图。markdown
这个是 React v15 的生命周期,你都掌握了吗?你知道 v16 有什么变化吗?网络
以前不管你去哪里面试,基本都会有几个必问问题:
生命周期最重要,可是有很高的学习成本,须要大量实践才能积累足够的经验。固然,这几个问题回答很差,百分之八十以上的概率会挂掉。
固然不止是生命周期,this 也是一个很大的问题。你有没有在组件写不少 bind
?或者全部的函数都用箭头函数定义?
this.someFunction = this.someFunction.bind(this);
// 或
someFunction = ()=>{}
复制代码
为何要这样写呢?若是不写会有什么问题?哎呦,又多了一个面试题,你会吗?
对比 Class,Hooks 的学习成本可就过低了!掌握了 useState 和 useEffect,80% 的事情就搞定了。
Class 业务逻辑分散,实现一个功能,我要写在不一样的生命周期里面,不聚合~
好比,若是你有个定时器,你必定要在 componentWillUnMount
去卸载。
再好比,咱们要写一个请求用户信息的组件,当userId
变化时,要从新发起请求。咱们就要在两个生命中期中写请求的逻辑。
相信上面的逻辑,你们也是常常会写的吧。
奥奥,sorry,上面的 componentWillReceiveProps
已经被废弃了,咱们应该用 componentDidUpdate
来代替。
“咦,这是为啥呢?好好的为何要废弃,不让这么用了?”
又来一个面试题!你知道答案吗?
而 Hooks 的业务逻辑就很是聚合了。上面的两个例子,改为 Hooks 你会写吗?
简直不要太简单!香啊!我能够提早下班了。
说到逻辑复用,不少同窗会说 Class 的 Render Props 和 HOC(高阶组件)能够作逻辑复用!那咱们看看 Class 的逻辑复用有多么的惨不忍睹。
首先咱们看看 Render Props。
首先咱们想复用监听 window size 变化的逻辑,开开心心的写了下面的代码。
而后,我又想复用监听鼠标位置的逻辑,我只能这么写了。
到这里你应该看到了问题所在。这简直就是地狱!我不忍心复用其它逻辑了。
咱们放过 Render Props,来看看 HOC 吧。
若是你要问什么是 HOC,那我不得不推荐个人另一篇文章《助你彻底理解React高阶组件(Higher-Order Components)》。
哪怕你不知道 HOC 是啥,你也必定用过。好比 redux 的 connect。
上面的代码,我用了三个 HOC,分别是 redux 的 connect,react-intl 的 injectIntl,以及 AntD 的 Form.create()。
这是一个很是常见的用法。若是你光看代码,大概已经懵圈了。“我是谁?我在哪?我要干什么?”
这会我仿佛听见 HOC 在说:“我不只让你看不懂我,我还很容易出各类问题。”
是的,HOC 很容易出问题。你们都往组件的 props 上面挂属性,万一有个重名的,那就只能说一句“很差意思,GG思密达”!
Hooks 来了,它表示,我要一个打五个!Render Props 和 HOC 联合起来也被我秒杀!
Hooks 表示,来十个,来一百个我也能打。
Hooks 最强的能力就是逻辑复用了,这是我最最最爱的能力了。
是的,我也不偏袒 Hooks,因为 React Hooks 的机制,若是用法不正确,会致使各类奇怪的闭包问题。
若是你要问 React Hooks 的机制是什么的话,我又要给你推荐一篇我以前写的文章了:《React Hooks 原理》。
那面对这个问题,怎么解呢?说实话,我也没有很好的解决办法。
可是,这可能也有好处。若是碰到想不明白的问题,那 99% 是因为闭包致使的,咱们有很肯定的方向去排查问题。
记住这句话,你能够少走不少弯路。
固然,说再多,吹再好,也没多大用。我上面讲的 Class 和 Hooks 的优缺点,网上的也有不少人讲,你们也确定都看过。
用程序员的交流方式,就是“Talk is cheap,Show me the code.”。
亮剑吧!
接下来,我会用一个例子,让你折服,拜倒在 Hooks 的石榴裙下。若是你不服,我们单独撕~
接下来,咱们来实现一个最最最多见的组件。该组件接收 userId,而后发起网络请求,得到用户信息。
说白了,就是最简单的发起网络请求的组件。咱们先用 Class 来实现看看。
这段代码,是最简单的网络请求。
美滋滋。可是少了点东西。网络请求,咱们确定要维护一个 loading 状态,保证用户体验比较好。
那咱们加上吧。
这张图,咱们增长了 loading 状态,在网络请求发起前,置为 true,在网络请求结束后,置为 false。
美滋滋。可是仍是少点东西。userId 变化后,我要从新发起网络请求吧。
咱们再加点代码吧。
咱们增长了对 userId 变化的监听,若是 userId 变化后,从新发起请求。
此次稳了吧?
不不不,还不够。若是 userId 连续变化了 5 次,发送了 5 个网络请求,咱们要保证老是最后一次网络请求有效。也就是常常说的的“竞态处理”或者“时序控制”。
我加!加还不行吗!
其实到这里,有些同窗已经懵了。“你说的时序控制,听着颇有道理,但我平时都没处理过这个问题,我看下你怎么实现的。”
确实,时序控制不算一个简单的问题,不少新手都不会解决这个问题。
稳了!到这里你以为稳了吧。
仍是年轻啊,小伙子。
若是用上面的代码来玩,你可能会偶尔碰到上面的警告。这个警告是怎么形成的呢?我说一下你就明白了。下面四个步骤执行,必会报警告:
看出问题了吗?组件已经卸载了,还去 setState,形成了内存溢出。
怎么解决呢?
在组件卸载的时候,放弃最后一次请求。
到这里为止,咱们就完成了一个完美的网络请求。此次真结束了!
看下写了多少行代码。
除去空格,咱们写了 38 行代码。实话说,38 行代码我能忍,可是这些逻辑我忍不了!回想下咱们处理了多少逻辑:
关键这些逻辑是没办法复用的!每一个项目可能有数十上百个组件会发网络请求,我就要写几十,几百遍这样的逻辑。想一想我都难受。
说实话,我在写项目的时候常常会偷懒。要不就不写 loading,要不就无论竞态,要不就无论最后的内存溢出警告。
你有没有和我同样呢?嘿嘿。
言归正传,接下来就邀请 Hooks 登场了。
三下五除二,咱们用 Hooks 实现了刚才全部的逻辑。
17 行!代码量减小了 50% 以上。好像还行!
可是,别忘了,Hooks 最重要的能力就是逻辑复用!这些逻辑咱们彻底能够封装起来!咱们把刚才的逻辑所有封装起来!
useAsync 封装了刚才咱们说的全部功能,一行代码完成了网络请求。
最后整个组件会长这样。
哇!我本身都佩服本身!简直了!美呆了,帅毙了,感受本身无敌了!提早完成工做,下班回家!
经过这个例子,我想证实一个论点:“使用 Hooks 封装逻辑的能力,能够极大提升开发效率”。
这时候你确定要问,useAsync 在哪里?给我瞧瞧?
useAsync 在这里,快来瞧,快来看啦!
useAsync 是 Umi Hooks 库的核心 Hooks 之一,Umi Hooks 提供了大量提炼自业务的 Hooks。一行代码真的能够实现不少功能!
固然,useAsync 不止包含上面说的功能,还支持“手动触发”执行,还支持“轮询”!
只要简单的配置一个 pollingInterval
,就能轮询发送请求了。快去试试啦!
接下来咱们会介绍几个更牛的 Hooks 给你们认识!
AntD 的 Table 组件,想必你们在项目中常常用到吧!除了刚才异步请求的全部逻辑外,你还得处理其它的逻辑。
好比维护 page、pageSize、sorter、filter 的状态,还得考虑搜索条件变化后,重置 page 到第一页。这些逻辑光想一想就头疼了,别说写了。
如今一行代码就能够实现了!useAntdTable,封装了全部的逻辑,只要一行代码!如图上所示,你只要 ...tableProps
,就能够了。这也许就是幸福的味道吧~
加载更多的场景,好比下面动图的场景,想必你们在工做中都写过。
这样一个加载更多的场景,咱们要维护多少状态?写多少行逻辑?原本我打算写个 Class 实现的例子贴出来的,可是我放弃了,由于太难了~~
随便想一想要处理的逻辑:
脑袋疼,真的脑袋疼。我会写,可是写起来真的好累。
还没完,通常产品同窗还会要求,上拉加载更多......
这时候咱们还得监听滚动位置,若是快到底了,触发加载更多。脑袋更疼了!
Umi Hooks 听到了你的求救,派出 useLoadMore 来拯救你了。一行代码就能够实现全部的功能!一个小时变一分钟,又能够早点下班了。
还有更好用的,好比 useDynamicList,下面的动态列表,一行代码搞定。
不只是上面讲到的各类复杂逻辑能够封装。简单的逻辑封装起来也是极其好用的,好比 Boolean 值的管理。
咱们通常控制 Modal,Popover 等显示隐藏的时候,都要维护一个 visible 状态。大概会是这样。
这样的逻辑,你写过多少遍?没有几千也有几百吧!
之后你就能够用 useBoolean 咯!
不只是上面讲到的这些,咱们还有不少不少的 Hooks。
好比 useSearch,就封装了一般异步搜索场景的逻辑,好比 debounce。
好比 useVirtualList,就封装了虚拟列表的逻辑。
好比 useMouse,封装了监听鼠标位置的逻辑。
好比 useKeyPress,封装了监听键盘按键的逻辑。
30+ Hooks 供您选择,而且咱们仍然处于婴儿期,快速发展中。咱们的愿景就是:封装别人的逻辑,让别人无逻辑可写。
如上面所述,咱们如今还处于婴儿期,须要不断汲取能量,更多的 Hooks 正在路上!要实现“让别人无逻辑可写”的目标,还需继续奋斗。
你们应该都听过 useSWR 吧?是 zeit 公司开发的一个专门作网络请求的 Hooks,提供了不少新颖的思路,给了咱们很是大的启发,github star 就像坐火箭同样。但在实际项目使用中,仍是会有不少地方不符合蚂蚁内部的体系。可是它给咱们很是大的启发,基于 swr 的思路,咱们能够实现更强大的 useRequest!图上的能力,咱们都要!
useRequest 目前已经处于内测期了,下个版本将会与你们见面!咱们的目标是:全部的网络请求,只用 useRequest 就够了!
目前社区上 Hooks 相关的基础教程、进阶教程、原理深刻、常见问题等文档都比较分散,咱们准备向 Hooks 生态发展,提供各式各样的文章。之后学习 Hooks,使用 Hooks,找 Umi Hooks 就对了。
固然,生态方面目前正在规划中,预计年后启动。
Umi Hooks,你值得拥有。
咱们目前处于发展阶段,欢迎你们一块儿共建。
你能够提 idea,咱们负责实现。
你能够提 issue,咱们负责改 bug。
你能够提 PR,将你封装的 Hooks 分享给你们,让更多人收益。
❤️期待您的参与。