背景
类组件,就是基于 ES6 Class 这种写法,通过继承 React.Component 得来的 React 组件。 函数组件顾名思义,就是以函数的形态存在的 React 组件。 所谓的 React-Hooks 就是函数组件内的钩子 useState、useEffect、useContext 等。
Why Hooks
Class 难以理解
this 和生命周期这两个痛点: this指向难以捉摸,有些时候花了很多时间都找不出来程序错在哪里,运行起来出现诡异的报错。为了解决 this 不符合预期的问题,各路前端也是各显神通,之前用 bind、现在推崇箭头函数。关于生命周期,React15和16版本就迭代了三次生命周期,需要消耗学习成本。
解决业务逻辑难以拆分的问题
类组件的业务逻辑可能会与生命周期耦合在一起。比如在 componentDidMount 里获取数据,在 componentDidUpdate 里根据数据的变化去更新 DOM 等。如果说你只用一个生命周期做一件事,那好像也还可以接受,但是往往在一个稍微成规模的 React 项目中,一个生命周期不止做一件事情。
componentDidMount() {
// 1. 这里发起异步调用
// 2. 这里从 props 里获取某个数据,根据这个数据更新 DOM
// 3. 这里设置一个订阅
// 4. 这里随便干点别的什么
// ...
}
componentWillUnMount() {
// 在这里卸载订阅
}
componentDidUpdate() {
// 1. 在这里根据 DidMount 获取到的异步数据更新 DOM
// 2. 这里从 props 里获取某个数据,根据这个数据更新 DOM(和 DidMount 的第2步一样)
}
像这样的生命周期函数,它的体积过于庞大,做的事情过于复杂,会给阅读和维护者带来很多麻烦。最重要的是,这些事情之间看上去毫无关联,逻辑就像是被“打散”进生命周期里了一样。比如,设置订阅和卸载订阅的逻辑,虽然它们在逻辑上是有强关联的,但是却只能被分散到不同的生命周期函数里去处理,这无论如何也不能算作是一个非常合理的设计。
而在 Hooks 的帮助下,我们完全可以把这些繁杂的操作按照逻辑上的关联拆分进不同的函数组件里:可以有专门管理订阅的函数组件、专门处理 DOM 的函数组件、专门获取数据的函数组件等。Hooks 能够帮助我们实现业务逻辑的聚合,避免复杂的组件和冗余的代码。
函数组件从设计思想上来看,更加契合 React 的理念
函数组件更加契合 React 框架的设计理念。React 组件本身的定位就是函数,一个吃进数据、吐出 UI 的函数。作为开发者,我们编写的是声明式的代码,而 React 框架的主要工作,就是及时地把声明式的代码转换为命令式的 DOM 操作,把数据层面的描述映射到用户可见的 UI 变化中去。这就意味着从原则上来讲,React 的数据应该总是紧紧地和渲染绑定在一起的,而类组件做不到这一点。