整理下 React Hooks

1. useState

这是我们开发中最常用的 hooks,我们用它进行状态管理,可以为组件添加一个状态。

用法

  const [state, setState] = useState(initialState)

  function initialStateFun() {
    return initialState
  }
  const [state, setState] = useState(initialStateFun)

这是 useState 的两种创建方式,我们可以在创建时传入一个初始值或者是初始化函数,初始化函数的返回值会作为初始值使用。

  • state 就是状态值
  • setState 是用来更新状态值的,setState 接受一个参数
  setState(nextState)
  setState((prevState) => prevState + 1)

setState 的参数可以是下一次的状态值,也可以是一个根据先前状态来计算下一次状态的函数,这个函数接受一个参数,参数是当前状态值,返回值是新的状态值。

当调用 setState 时就可以触发组件的重新渲染。

注意事项

  1. setState 更新的是下一次的状态,也就是当你调用完 setState 后马上去读取 state 那么读取到的还是当前的状态。也就是他是一个异步操作。

  2. 如果在 setState 中你提供的新状态与旧状态相同那么 React 将会跳过该组件及其子组件的重新渲染,React 会用Object.is来对比。这是一种优化。

  3. React 会批量处理更新状态,它会在所有事件处理函数运行并调用其 setState 函数后再更新屏幕。这可以避免频繁的重新渲染。

  4. 在严格模式中,initialStateFun 会执行两次,你在 setState 中传入的函数也会被调用两次,这个是开发时的行为不会影响生产环境。

2. useEffect

useEffect 将组件与外部系统同步,我通常使用它与服务器进行通信。

用法

useEffect(() => {}, [])

接收两个参数:

  1. setup 函数:分别在组件挂载和 dependencies 更新时执行。这个函数返回一个函数 cleanup,会在组件卸载或者更新时执行 setup 函数之前执行,通常我会在这里取消订阅或者清理一些副作用。

  2. dependencies 数组:这里放入 useEffect 的依赖项,在组件渲染时 React 会根据依赖项是否变化来决定是否执行 setup 函数。

注意事项

  1. Effect 通常会在浏览器绘制页面之后执行

  2. 当 Effect 是由一些用户交互引起时(点击、键盘输入等),在 React 中这些事件优先级比较高,所以 React 可能会在浏览器渲染之前执行,如果你需要他在浏览器绘制之后执行可以使用 setTimeout。注意是可能并不是一定,如果需要确定的在浏览器绘制之前执行那么应该使用 useLayoutEffect,这个 hooks 会在浏览器绘制之前执行。

3. useLayoutEffect

useEffect 用法相同,但是执行时机不同,通常 useEffect 在浏览器渲染之后执行,而 useLayoutEffect 在浏览器渲染之前,所以他会阻塞浏览器渲染。如果使用不得当可能会导致性能问题。

用法

useLayoutEffect(() => {
  // 在浏览器绘制之前执行
  return () => {
    // cleanup 函数
  }
}, [dependencies])

注意事项

  1. useLayoutEffect 会在所有 DOM 变更之后同步执行,在浏览器绘制之前执行
  2. 会阻塞浏览器绘制,如果使用不当可能导致性能问题
  3. 通常用于需要同步读取 DOM 布局并重新渲染的场景

4. useRef

useRef 用来操作组件或者是存储一些不会展示在视图中的状态,因为在改变时不会触发组件更新。

用法

const ref = useRef(initialValue)

useRef 可以接收一个初始值,返回一个带有 current 属性值的对象,我们使用时用的就是这个属性。

  • current: 初始值为接受的值,之后可以设置为其他值,如果将 ref 作为一个 JSX 节点的 ref 属性传递,React 将为它设置 current 值。

React 内置支持对原生 DOM 的操作:

const ref = useRef<HTMLInputElement>(null);

return (
  <input ref={ref} />
)

注意事项

  1. useRef 返回的对象在组件的整个生命周期中保持不变
  2. 改变 ref.current 不会触发组件重新渲染
  3. 可以用于存储定时器 ID、DOM 引用等不需要触发渲染的数据

5. useCallback、useMemo

这两个 hooks 用来在组件的渲染中缓存,它们接收的参数是一个函数和一个依赖数组,useCallback 缓存函数,useMemo 缓存函数的返回值。如果你想避免一些不必要的计算或者是重新渲染,可以使用这两个 hooks,如果要避免一些重新渲染可能需要配合 memo 一起使用。