React Hooks 基础使用记录

最近开始在项目中完成了一轮 React Hooks 升级,记录一下 React Hooks 的基础使用。

React Hooks

1. 什么是 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

2. 从 class 切换到 React Hooks

  1. 构造函数 constructor
    • React Hooks 不需要构造函数
    • 内部无状态的变量 直接用 let var const 定义即可
    • 内部有状态的变量 使用 useState
    • 使用 useState 可以传入一个初始始
    • 可以将 class 里面的 state 按功能分组,使用多个 useState
    • useState 还支持传入一个方法,返回初始 state.
  2. render 方法:
    • React Hooks 不再需要重写 render 方法,直接返回即可
    • Hook 函数传入的参数,即为 class 的 props
  3. 生命周期 componentDidMount , componentDidUpdate , componentWillUnmount
    • 使用 useEffect Hook 可以完全实现上面三个周期的所有功能
    • useEffect 支持两个函数,
    • 第一个参数同时具备 componentDidMount 和 componentDidUpdate,
    • 第二个参数为 componentWillUnmount ,不需要可不传
  4. ref 方法
    • 组件的 ref 方法也是可以像原来那么写
    • Hook 支持 useRef
  5. 生命周期 shouldComponentUpdate
    • 需要使用 React.memo,这点虽然支持,但写法上复杂于 class 了
    • const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
  6. 还有一些生命周期,现在(2022-04-24) React Hooks 还不支持。不过说未来可以支持。
    • componentDidCatch
    • getSnapshotBeforeUpdate
    • getDerivedStateFromError
    • 我只用过 componentDidCatch,而且只在少数组件里面用,所以感觉影响不大。

3. React Hooks 的好处

Hooks 相对于 class 好处有如下几点:

  1. 复用性强 相对于 class 写法, 对应的设计思想是:组合优于继承
    • Hooks 可以根据不同的功能拆分的很细,便于不同的组件取用。
    • 而 class 需要复用则需要通过继承的方式。
    • 其实,组合优于继承,这句话并非任何场景都绝对正确,有时候还需要根据场景灵活使用。
  2. class 在写法上有优势也有劣势
    • 需要写很多的 this ,对于 JavaScript 这种函数语言来说,有点强人所难
    • 面实际上 class 经过 webpack 等工具后,最终产出还是 function,编译器为保障正确性,会多出一些冗余。
    • 有些专门经过 class 优化的代码可能会失效,总体来说,性能弱于 纯function。
  3. 写法简单,从代码量就可以看出来。
    • 当然不得不说,这容易把组件的结构逻辑弄复杂。
    • 可能 Hooks 的最佳实践会是大量组件的组合嵌套,让每个组件都只干自己的一小部分逻辑。
    • 有些 Hooks 如 useEffect,在 class 里面重写好几个函数才能实现对应的功能
  4. 简易的功能
    • Hooks 除了提供基础 Hooks 外,额外提供了十几个扩展 hooks, 如 useReduceruseCallbackuseLayoutEffect 等等
    • 功能方面,虽然 class 本身也能做到,但是仍不如直接提供的 hooks 简单

4. React Hooks 使用小结

  1. Hook不能出现在 class 写法里面,调用只能出现函数首层,比如以下通过条件运行就是不支持的。
if (name !== '') {
    useEffect(function persistForm() {
      localStorage.setItem('formData', name);
    });
}
  1. class 写法优点组件的生命周期比较明确,如果是需要管理较复杂的周期的组件,用 class 组件会清晰一些,而且现在 Hooks 已经发布有3年了,还有一个比较重要的周期事件 componentDidCatch 没有得到支持。

  2. 在 Hooks 层面进行性能优化和 class 的优化,逻辑思路是一样的,但在技术手段上有很大的区别,需要根据情况解决。

  3. 开始一个新项目时,建议从 Hooks 启动,大部分场景下, Hooks 优于 class。

个人感觉吧,React 最初的 class 应该是一个卖点,面向对象式的编程方式会让很多 Java/C# 程序员非常有亲切感。

但 Java 这种语言广受吐槽的语法啰嗦,容易类爆炸这样的一些缺点,对于变化快的前端也是很难接受的,面向对象式编程和函数式编程,其实对应两种思想,不应有优劣之分。

Hook 相当于给了你一个大盒子,什么东西都可以放在这个盒子里面。

而 Class 相当于给了你几个小抽屉,放东西时先想好需要放在哪个抽屉里面。

在简单的情况下,可能常用的就一两个抽屉,剩下的都没有用过,用抽屉就会显得复杂。

在复杂的情况下,什么都西都网盒子里面塞,盒子里面的东西就会混乱。