前期准备

要把 reactreact-dom 更新到 16.7.0-alpha 及以上,如果配置了 ESLint,记得添加对应的 Plugin
(安装插件能够帮助你不弄错每个盒子和状态的对应关系,书写的时候 Hooks 需要 use 开头且放在顶层作用域,即不可以包裹 if/switch/when/try 等)

React Hooks 的本质

  • Hooks 本质是把面向生命周期编程变成了面向业务逻辑编程

  • Hooks 使用上是一个逻辑状态盒子,输入输出表示的是一种联系;

  • Hooks 是 React 的未来,但还是无法完全替代原始的 Class。

面向生命周期编程 =》面向业务逻辑编程
React Hooks - 图1 == ===》React Hooks - 图2

业务逻辑复用

这里说的业务逻辑复用主要是需要跨生命周期的业务逻辑。单单按照组件堆积的形式组织代码虽然也可以达到各种复用的目的,但是会导致组件非常复杂,数据流也会很乱。组件堆积适合 UI 布局,但是不适合逻辑组织。为了解决这些问题,在 React 发展过程中,产生了很多解决方案,

Mixins

坏处远远大于带来的好处,因为现在已经不再支持,不多说,可以看看这篇文章:Mixins Considered Harmful

Class Inheritance

官方 很不推荐此做法

High-Order Components (HOC)

React 高阶组件 在封装业务组件上简直是屡试不爽,它的实现是把自己作为一个函数,接受一个组件,再返回一个组件,这样它可以统一处理掉一些业务逻辑并达到复用目的。

比较常见的一个就是 react-redux 里的 connect 函数:
React Hooks - 图3
但是在调试的时候可以看到会产生“组件嵌套地狱”
React Hooks - 图4

Render Props

Render Props 其实很常见,比如 React Context API

  1. class App extends React.Component {
  2. render() {
  3. return (
  4. <ThemeProvider>
  5. <ThemeContext.Consumer>
  6. {val => <div>{val}</div>}
  7. </ThemeContext.Consumer>
  8. </ThemeProvider>
  9. )
  10. }
  11. }

它的实现思路很简单,把原来该放「组件」的地方,换成了回调,这样当前组件里就可以拿到子组件的状态并使用。

但是,同样这会产生 Wrapper Hell 问题:
React Hooks - 图5

状态盒子

Hooks 只能在其它 Hooks 的函数或者 React Function 组件里。

React 社区一直推崇函数式、纯函数等思想,引入 Hooks 概念后的 Functional Component 变的不再纯了,useXxx 与其说是一条执行语句,不如说是一个声明。声明这里放了一个「状态盒子」,盒子有输入和输出,剩下的内部实现就一无所知,重要的是,盒子是有记忆的,下次执行到此位置时,它有之前上下文信息。

类比「代码」和「程序」的区别,前者是死的,后者是活的。表达式 c = a + b 表示把 ab 累加后的值赋值给 c,但是如果写成 c := a + b 就表示 c 的值由 ab 相加得到。看起来表述差不多,但实际上,后者隐藏着一个时间的维度,它表示的是一种联系,而不单单是个运算。这在 RxJS 等库中被大量使用。

这种声明目前是通过很弱的 use 前缀标识的(但是设计上会简洁很多),为了不弄错每个盒子和状态的对应关系,书写的时候 Hooks 需要 use 开头且放在顶层作用域,即不可以包裹 if/switch/when/try 等。如果你按文章开头引入了那个 ESLint Plugin 就不用担心会弄错了。

Fragment

Wrapper Hell,我个人觉得使用 Fragment 也可以基本解决。

案例讲解

功能需求

根据 input 的输入值更改网页的 title 信息

Class Component

  1. import React from 'react'
  2. class ChangeTile extends React.Component {
  3. constructor(props) {
  4. super(props)
  5. this.state = {
  6. title = ''
  7. }
  8. }
  9. handleChage(title) {
  10. this.setState({
  11. title
  12. })
  13. }
  14. render() {
  15. return (
  16. <div>
  17. <input value={this.state.title} onChange={this.handleChage(title)} />
  18. </div>
  19. )
  20. }
  21. }

Hooks 写法

后记

HOC 和 Render Props 还是有存在的必要,一方面是支持 React Class,另一方面,它们不光适用于纯逻辑封装,很多时候也适合逻辑 + 组件的封装场景,虽然此时使用 Hooks 也可以,但是会显得啰嗦点。

参考资源

官网文档
Making Sense of React Hooks
https://www.yuque.com/es2049/blog