Jacleklm's Blog

React - Hook

2020/05/23

本文大部分来自ConardLi 的 blog,建议直接看原博客

What & Why

使用 Hooks,你可以在将含有 state 的逻辑从组件中抽象出来,这将可以让这些逻辑容易被测试。同时,Hooks 可以帮助你在不重写组件结构的情况下复用这些逻辑。所以,它也可以作为一种实现状态逻辑复用的方案
解决了 HOC 嵌套地狱的问题,使得逻辑复用更加清晰

State Hook

useState 是一个钩子,他可以为函数式组件增加一些状态,并且提供改变这些状态的函数,同时它接收一个参数,这个参数作为状态的默认值

Effect Hook

Effect Hook 可以让你在函数组件中执行一些具有 side effect(副作用)的操作

参数

  • 第一个参数是回调函数,在第组件一次 render 和之后的每次 update 后运行,React 保证在 DOM 已经更新完成之后才会运行回调;这个回调函数可以 return 一个函数,在执行下一个 useEffect 之前,会执行这个函数,常常用来对上一次调用 useEffect 进行清理,并且可以拿到上一次的状态(原理是闭包)
  • 第二个参数是状态依赖

作用

模拟生命周期

  • componentDidMount:状态依赖为空数组即可(其实官方并不推荐这种写法)
1
2
3
function useDidMount(callback) {
useEffect(callback, [])
}
  • componentWillUnmount:作为回调函数的 return 函数
1
2
3
function useUnMount(callback) {
useEffect(() => callback, [])
}

ref Hook

用来获取 DOM 的 ref

1
2
3
4
5
6
7
8
9
10
11
12
export default function Input() {
const inputEl = useRef(null)
const onButtonClick = () => {
inputEl.current.focus()
}
return (
<div>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</div>
)
}

注意 useRef()并不仅仅可以用来当作获取 ref 使用,使用 useRef 产生的 ref 的 current 属性是可变的,这意味着你可以用它来保存一个任意值

模拟 componentDidUpdate

componentDidUpdate 就相当于除去第一次调用的 useEffect,我们可以借助 useRef 生成一个标识,来记录是否为第一次执行:

1
2
3
4
5
6
7
8
9
10
function useDidUpdate(callback, prop) {
const init = useRef(true)
useEffect(() => {
if (init.current) {
init.current = false
} else {
return callback()
}
}, prop)
}

自定义 Hook

自定义 Hook 非常简单,我们只需要定义一个函数,并且把相应需要的状态和 effect 封装进去,同时,Hook 之间也是可以相互引用的。使用 use 开头命名自定义 Hook,这样可以方便 eslint 进行检查。
自定义 Hook 不需要具有特殊的标识。我们可以自由的决定它的参数是什么,以及它应该返回什么(如果需要的话)。换句话说,它就像一个正常的函数

使用 Hook 的动机

  • 减少状态逻辑复用的风险
    • 多个 Hook 之前不会相互影响,不会相互覆盖;Hook 也可以避免 HOC 使用不规范时的 props 覆盖
  • 避免嵌套地狱
  • 让组件更容易理解:能用 Hook 讲公共逻辑抽离成函数,将一个组件分割成更小的函数,而不是强制基于生命周期方法进行分割
  • 函数代替 class

注意点

  • useState 的 setXX 是异步函数,所以 setXXX 后立刻 console.log(XXX)的话是得不到的
  • 在 setTimeout 这种闭包中中读不到其他状态的新值
  • 记住 Hook 不能写在条件(if),循环(for),和嵌套函数中使用

参考资料
ConardLi 的 blog
官方文档

CATALOG
  1. 1. What & Why
  2. 2. State Hook
  3. 3. Effect Hook
    1. 3.1. 参数
    2. 3.2. 作用
      1. 3.2.1. 模拟生命周期
  4. 4. ref Hook
    1. 4.1. 模拟 componentDidUpdate
  5. 5. 自定义 Hook
    1. 5.1. 使用 Hook 的动机
  6. 6. 注意点