转自:zouwowo前端
juejin.cn/post/6907189103151087623vue
前言react
本文不会有React
具体应用的内容,只是一些对于hooks
跟以前的类组件的比较,对于hooks
自己的思考。web
笔者在今年的8月份入职如今的公司,从原来的vue
转为React
。由于公司还存在一些比较老的项目,因此前期并无彻底投入到React
的项目开发当中。从10月份开始,参与了一个公司层面的新项目从0到1的构建过程,这也是我第一个React
项目。咱们是全面拥抱hooks
的,这个项目的开发过程当中,我也写了不少自定义的hooks
方法,封装了好几个通用的功能组件,也算是熟练了React
的具体应用。编程
项目开发初期,我一直有个疑惑,我在入职以前学习React
的时候,其实不少的教程都是使用的类组件的方法,不多看到hooks
的相关教程。本身边学边写demo的时候使用的也都是类组件的写法,可是如今愈来愈多的团队开始全面拥抱hooks
,hooks
到底有什么优势?我将在下面提出一些本身的思考和想法。api
类组件和函数组件区别
这里要注意,类组件
和hooks
,这两个东西其实并非一个概念。hooks
只是一个工具集,用来加强函数组件的功能。真正要对比的应该是类组件
和函数组件
。数组
咱们先来看看类组件
和函数组件
的区别。性能优化
代码写法上的区别
这是最直观的区别,代码就长的不同嘛。我随便列几个很常见的例子,这些特性在函数组件
里都没有。微信
-
类组件,顾名思义,它就是一个类,须要继承 Class
。 -
类组件能够直接定义state -
类组件有生命周期方法 -
类组件可使用this获取到组件实例
心智模型上的区别
这是两个组件之间最大的区别,用https://overreacted.io/zh-hans/how-are-function-components-different-from-classes/
中的话来讲。闭包
函数式组件捕获了渲染所用的值。
咱们引用文章里的一个例子
function ProfilePage(props) {
const showMessage = () => {
alert('成功关注 ' + props.user);
};
const handleClick = () => {
setTimeout(showMessage, 3000);
};
return (
<button onClick={handleClick}>关注</button>
);
}
复制代码
class ProfilePage extends React.Component {
showMessage = () => {
alert('成功关注 ' + this.props.user);
};
handleClick = () => {
setTimeout(this.showMessage, 3000);
};
render() {
return <button onClick={this.handleClick}>关注</button>;
}
}
复制代码
咱们用类组件
以及函数组件
实现了同一个逻辑。这两个组件都会接收一个props.user
的属性,咱们点击按钮,在3秒以后,会alert
一条成功关注的信息。
假如一开始传入的props
的值是 { user: '帅wowo' }
,而后咱们点击关注按钮,在3秒以内,传入的props
值变化了,变成了{ user: '丑wowo' }
。这两个组件将分别alert
出什么内容?
有过经验的同窗确定能轻松答出来。
// 函数组件会打印
'成功关注 帅wowo'
// 类组件会打印
'成功关注 丑wowo'
复制代码
为何会这样呢?(这里注明一下,这个例子跟React
框架无关,只是js
的基本特性,你在任何用js
编写的代码中均可以复现)
在React
的类组件中,props
虽然是不变的,可是this
永远是可变。当有异步的事件触发,它获取到的props
或者state
永远都是最新的。固然咱们也有办法去解决。
好比咱们能够从新定义一个数据来保存`props
handleClick = () => {
const {user} = this.props;
setTimeout(() => this.showMessage(user), 3000);
};
复制代码
但这种方式太过繁琐,各类定义的数据很是不够优雅。
或者把事件都写到渲染函数render
中
class ProfilePage extends React.Component {
render() {
const props = this.props;
const showMessage = () => {
alert('成功关注 ' + props.user);
};
const handleClick = () => {
setTimeout(showMessage, 3000);
};
return <button onClick={handleClick}>关注</button>;
}
}
复制代码
这个方法其实函数组件的原理,props
变化以后,组件虽然从新渲染了,可是老的props
经过闭包保存了下来,而后被打印出来。
写了这么多,只是为了论证那句话,函数式组件捕获了渲染所用的值。
为何咱们要使用函数组件+hooks
这一点不少人可能以为不必,以为官方出的东西,跟着用就好,写着也挺顺手的,还管啥为何呢?
关于这一点,我以为最重要的其实就是学习大佬们的思惟,为何要作出一个hooks
来?确定是为了解决一些原来的开发过程当中的问题。React
团队的设计层面的思路,可以在必定程度上表明当前业界在框架设计领域里最佳实践。
接下来我会列出几个我认为的类组件
的几个痛点。(好和坏都是比较出来的,这些痛点只是相比于函数组件+hooks而言
,技术在不断发展,技术的迭代都是正常的趋势)
1.函数组件的写法更轻量,更加灵活
在函数组件中,咱们不须要去继承一个class
对象,不须要记忆那些生命周期,不须要固定的把数据定义在state
中。函数做为js中的一等公民,函数式编程方式可让咱们能够更加灵活的去组织代码。
2.类组件存在自身的缺陷
一个其实就是上面一节写到,若是咱们须要一个只跟着视图走的数据,咱们不能直接使用props
或者state
。
还有一个是最多见的,在React
中,若是咱们定义一个方法,咱们必须使用bind
或者箭头函数去约束这个方法的this
的做用域。
这两个问题虽然咱们都能解决,可是本质上,都是咱们经过代码实践的方式去解决类组件
自身的缺陷。
可是在函数组件中,咱们不会有这种问题,经过闭包的方式,在一次渲染中,组件的props
和state
是保持不变的,并且传递的方法自己就是已经被约束做用域了。
3.逻辑是分散的,并且难以复用
这个痛点其实跟vue2
是如出一辙的,React
的类组件和vue2
的开发模式都是相似。
我拿一张尤大来谈论vue2
和vue3
区别时候的一张图来举例
这里的不一样颜色其实就是不一样逻辑,这图能够分红数据,事件方法,生命周期,模板四块内容。
咱们能够看到,一个逻辑在类组件里实际上是分散的,拿React
来讲,数据须要定义在state
里,而后须要编写相关的事件方法,再在生命周期里进行逻辑的初始化,组件更新时候的处理,最后在模板里写jsx
。
咱们若是是去维护这个代码,会很痛苦,为了查看一个逻辑,咱们要上下翻,找出各自的数据,方法,生命周期和模板。
并且这种方式的代码,很难被复用,抽离重复逻辑咱们经历过mixin
,HOC & render-props
。这两种方式都有一个最大的问题,那就是props
的来源不够清晰。mixin
就不说了,都是泪,只能一个个去找。HOC
嵌套层级一多,也会很难肯定来源,并且HOC
的学习成本也相对比较高,对于新手不太友好。(这块是按我vue2
开发用到的mixin
和HOC
的经验写的,我做为React
的新手,并无经历过React
的mixin
和HOC
抽离逻辑的时代,因此若是写的有问题,请各位大佬指出。最后感叹一句,React
用HOC
可太方便了!)
可是若是咱们使用hooks
,我仍是用一张vue3
中组合式API的图来讲明,跟使用hooks
的结果是相似的。

每块逻辑都是一个总体,很是清晰明了。并且你能够把这些逻辑都抽离出去,只是在这个组件当中引用便可。
逻辑复用就不用说了,如今谁家React
项目里没有好多自定义的hooks
啊。
4.hooks更贴合React的基本理念
React的设计理念 里第一条
React的核心理念之一,相同的参数输入应该产生相同的输出。简单说,它应当是一个简单的纯函数。
咱们能够拿以前说到的心智模型上的区别中的例子来讲明,咱们传入一个props
参数{ user: '帅wowo' }
,咱们但愿关于这个参数的全部事件都强依赖于这条数据。它不该该像类组件
同样,传入的参数和咱们获得的输出不一致。
可是函数组件能够作到,重复引用一下上面的一句话,在一次渲染中,组件的props
和state
是保持不变的。
hooks的不足
谈论一个技术,咱们不能太过于片面,必定要保持辩证思惟,理性分析。上面说了不少hooks
的优势,可是它依然存在着不足。
1.比较大的心智负担
一样是由于上面那句话,在一次渲染中,组件的props
和state
是保持不变的。这个特性致使的闭包陷阱
是咱们如今开发中最多见的一个问题。咱们须要时刻注意是否已经给hooks
添加了必要的依赖项。在封装一些功能相对复杂的组件时,useEffect
的重复渲染问题处理有时候会很是棘手,并且不易调试。
这个特性在对函数组件
进行性能优化时也是会带来很大的麻烦,由于每次props
和state
数据变化,都会致使函数组件
中全部内容的从新渲染。咱们须要经过memo
,useMemo
,useCallback
这些方法手动去减小组件的render
。当一个组件结构比较复杂,嵌套较多时,依赖项问题的处理也很让人头疼。具体性能优化的内容,能够看我以前的文章。
这些点给开发者带来的学习hooks
的成本相比较类组件
来讲会更大。
2.须要更严格的开发规范
刚才咱们说了,函数式编程可以给咱们带来很大的灵活度,这个灵活度在开发当中是一个双刃剑。它能帮助咱们更好的去解决一些复杂的需求,可是它在一个多人协做开发的项目中并非一个好的事情。
一些大型的项目,最重要的必定是编程的规范,eslint
能够限制语法规范,可是限制不了咱们实现需求的规范,一人一个风格的代码对于一个项目来讲就是个灾难,对于后续的维护,公共方法的抽离来讲将带来很大的麻烦。
因此,须要开发者制定一个具体的开发规范,并在开发的时候严格遵照。
3.hooks并不能彻底代替类组件
虽然咱们有了不少hooks
方法,用来加强函数组件
的功能。好比useState
可让函数组件
维护本身的数据。有useEffect
能够在必定程度上弥补函数组件
没有生命周期的缺点。
注意:useEffect
并非用来代替生命周期,它只是提供了一个相似生命周期的方法。二者其实本质上没有可比性。
想了解更多,能够看Dan的这篇博客,https://overreacted.io/zh-hans/a-complete-guide-to-useeffect/
,它能够帮你更好的理解hooks
中的useEffect
。
可是,咱们仍是不能拿hooks
来彻底代替类组件。(主要是部分生命周期还没法被代替)
好比componentDidCatch
这个获取组件错误的生命周期,在大部分的项目中,确定会看到它的身影。还有其余的一些生命周期,可能你在一些特殊的场景下仍是须要用到。
因此,在一段时间以内,hooks
仍是会跟类组件
共存。
总结
愈来愈多的公司和团队早已经全面拥抱hooks
,如今再谈论使用hooks
的收益跟付出相比是否值得已经毫无心义,大的潮流已经给你指明了方向,今年新发布的正式版vue3
也是借鉴了hooks
的方式,实现了让开发者使用组合式api的方式组织逻辑代码。大势所趋,你也得赶忙跟上。
感谢,求赞
感谢您的阅读,若是以为本文对你有所帮助的话,请动手点个赞支持一下,谢谢。
点赞和在看就是最大的支持❤️
本文分享自微信公众号 - 前端技术江湖(bigerfe)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。