最近开始在项目中完成了一轮 React Hooks 升级,记录一下 React Hooks 的基础使用。
什么是 React Hooks
在写 React 组件时,有两种方法:
一种是常用的 class 写法形式,例如:
class XXX extends React.Component {
render(){
return xxx
}
}
很多组件都很简单,写成 class 有点多余,更简单的写法是写成一个函数,像这样:
const XXX = (props) => <div>{props.xxx}</div>
这种简单的方法,虽然看上去很清爽,但有一个小问题:只能写简单的组件
比如,我在写成 class 时,可以用 setState
, componentDidMount
, componentDidUpdate
之类的方法来丰富组件内容,管理组件的生命周期,而使用函数式的写法时,只能进行展示,做不了复杂的工作。
为了保持简单的写法的同时,也可使用组件复杂的功能,于是就有了 React Hooks
从 class 切换到 React Hooks
- 构造函数
constructor
:- React Hooks 不需要构造函数
- 内部无状态的变量 直接用
let
var
const
定义即可 - 内部有状态的变量 使用
useState
- 使用
useState
可以传入一个初始始 - 可以将 class 里面的 state 按功能分组,使用多个
useState
useState
还支持传入一个方法,返回初始 state.
- render 方法:
- React Hooks 不再需要重写
render
方法,直接返回即可 - Hook 函数传入的参数,即为 class 的 props
- React Hooks 不再需要重写
- 生命周期
componentDidMount
,componentDidUpdate
,componentWillUnmount
- 使用
useEffect
Hook 可以完全实现上面三个周期的所有功能 - useEffect 支持两个函数,
- 第一个参数同时具备 componentDidMount 和 componentDidUpdate,
- 第二个参数为 componentWillUnmount ,不需要可不传
- 使用
- ref 方法
- 组件的 ref 方法也是可以像原来那么写
- Hook 支持
useRef
- 生命周期
shouldComponentUpdate
- 需要使用 React.memo,这点虽然支持,但写法上复杂于 class 了
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
- 还有一些生命周期,现在(2022-04-24) React Hooks 还不支持。不过说未来可以支持。
- componentDidCatch
- getSnapshotBeforeUpdate
- getDerivedStateFromError
- 我只用过
componentDidCatch
,而且只在少数组件里面用,所以感觉影响不大。
React Hooks 的好处
Hooks 相对于 class 好处有如下几点:
- 复用性强 相对于 class 写法, 对应的设计思想是:组合优于继承。
- Hooks 可以根据不同的功能拆分的很细,便于不同的组件取用。
- 而 class 需要复用则需要通过继承的方式。
- 其实,组合优于继承,这句话并非任何场景都绝对正确,有时候还需要根据场景灵活使用。
- class 在写法上有优势也有劣势
- 需要写很多的 this ,对于 JavaScript 这种函数语言来说,有点强人所难
- 面实际上 class 经过 webpack 等工具后,最终产出还是 function,编译器为保障正确性,会多出一些冗余。
- 有些专门经过 class 优化的代码可能会失效,总体来说,性能弱于 纯function。
- 写法简单,从代码量就可以看出来。
- 当然不得不说,这容易把组件的结构逻辑弄复杂。
- 可能 Hooks 的最佳实践会是大量组件的组合嵌套,让每个组件都只干自己的一小部分逻辑。
- 有些 Hooks 如 useEffect,在 class 里面重写好几个函数才能实现对应的功能
- 简易的功能
- Hooks 除了提供基础 Hooks 外,额外提供了十几个扩展 hooks, 如
useReducer
,useCallback
,useLayoutEffect
等等 - 功能方面,虽然 class 本身也能做到,但是仍不如直接提供的 hooks 简单
- Hooks 除了提供基础 Hooks 外,额外提供了十几个扩展 hooks, 如
React Hooks 使用小结
- Hook不能出现在 class 写法里面,调用只能出现函数首层,比如以下通过条件运行就是不支持的。
if (name !== '') {
useEffect(function persistForm() {
localStorage.setItem('formData', name);
});
}
class 写法优点组件的生命周期比较明确,如果是需要管理较复杂的周期的组件,用 class 组件会清晰一些,而且现在 Hooks 已经发布有3年了,还有一个比较重要的周期事件
componentDidCatch
没有得到支持。在 Hooks 层面进行性能优化和 class 的优化,逻辑思路是一样的,但在技术手段上有很大的区别,需要根据情况解决。
开始一个新项目时,建议从 Hooks 启动,大部分场景下, Hooks 优于 class。
如何选择
个人感觉吧,React 最初的 class 应该是一个卖点,面向对象式的编程方式会让很多 Java/C# 程序员非常有亲切感。
但 Java 这种语言广受吐槽的语法啰嗦,容易类爆炸这样的一些缺点,对于变化快的前端也是很难接受的,面向对象式编程和函数式编程,其实对应两种思想,不应有优劣之分。
Hook 相当于给了你 一个大盒子,什么东西都可以放在这个盒子里面。
而 Class 相当于给了你 几个小抽屉,放东西时先想好需要放在哪个抽屉里面。
- 在简单的情况下,可能常用的就一两个抽屉,剩下的都没有用过,用抽屉就会显得复杂。 (使用Hook)
- 在复杂的情况下,什么都西都网盒子里面塞,盒子里面的东西就会混乱。 (使用Class)