14-Hook及useState

202 阅读3分钟

Hook简介

  • hook是react16.8之后出现的

组件分为

  • 无状态组件(函数组件)
  • 类组件

类组件中的麻烦

  • this指向的问题(bind、箭头函数的形式)
  • 繁琐的生命周期(需要理解记忆)
  • 其它问题后面结合代码说

Hook 专门用于增强函数的功能(不能在类组件中使用),使之理论上可以成为类组件的替代品

  • 官方强调:没有必要去更改已经完成的类组件,官方没有计划取消类组件,只是鼓励使用类组件
  • hook(钩子)本质上是一个函数(命名总是已use开头),改函数可以挂载任何功能
  • 不同的hook有不同的功能

Hook种类

  • useState、useEffect等后面笔记补充

useState

  • 用于在函数组件中使用状态
  • useState函数有一个参数,这个参数的值表示状态的默认值
    • 无值默认 undefined
  • 返回值是一个数组,该数组包含2项
    • 第一项: 当前状态的值
    • 第二项: 改变状态的函数
  • 一个函数组件可以又多个状态,这种做法非常有利于横向切关注点
import React, { useState } from 'react'

export default function StateHook() {
  const [num, setNum] = useState(0)
  const [isShow, setShow] = useState(true)
  return (
    <div>
      <div style={{ display: isShow ? 'block' : 'none' }}>
        <button onClick={() => setNum(num - 1)}>-</button>
        <span>{num}</span>
        <button onClick={() => setNum(num + 1)}>+</button>
      </div>
      <button onClick={() => setShow(!isShow)}>显示/隐藏</button>
    </div>
  )
}

image.png

state 原理图

  • 函数运行有一个特点,内部的代码会全部运行,怎么保持住状态的
  1. 原理图如下,对应上面的代码 image.png

注意细节

  • 多多少少跟它的原理有关系
  1. useState最好写在函数的起始位置,便于阅读
  2. useState严禁出现在代码块(判断、循环)中
  3. useState返回的函数(数组的第二项引用不变,节约内存空间)
  4. 使用函数改变数据,如果数据和之前的数据完全相等(使用Object.is比较),不会导致重新渲染,以达到优化效率的优点
  5. 使用函数改变数据,传入的值不会和原来的数据合并,而是直接替换
  6. 逻辑不是一块(状态之间没有必然联系)的数据建议切分,不要写在一块
import React, { useState } from 'react'

export default function StateHook() {
  const [data, setData] = useState({
    x: 1,
    y: 1
  })
  return (
    <div>
      <div>x: {data.x} --- y: {data.y}</div>
      <button onClick={() => {
        setData({
          ...data,
          x: data.x + 1
        })
      }}>X</button>
      <button onClick={() => {
        setData({
          ...data,
          y: data.y + 1
        })
      }}>Y</button>
    </div>
  )
}
  1. 如果要实现强制刷新组件
    • 7.1 类组件中: 使用this.forceUpdate()函数(不推荐),不会运行shouldComponentUpdate
    • 7.2 函数组件: 可以使用空对象,因为地址不一样了
function XX () {
  const [,forUpdate] = useState({})
  return (
     <>
         <button onClick={() => {
             forUpdate({})
         }}>强制刷新</button>
     </>
  )
}
  1. 和类组件一样,函数组件中改变状态可能是异步的(在DOM事件中),多个状态变化会合并以提高效率,此时不能信任之前的状态,而是使用回调函数的方式
import React, { useState } from 'react'

export default function StateHook() {
  console.log('render !!!')
  const [num, setNum] = useState(0)
  return (
    <div>
      <div>
        <button onClick={() => {
          setNum(num - 1)
          setNum(num - 1)
        }}>-</button>
        <span>{num}</span>
        <button onClick={() => {
          setNum(num + 1)// 不会立即变化,事件运行完成之后一起变化
          setNum(num + 1)// 此时 n 的值还是 0 -> 1
        }}>+</button>
        //正确做法如下
        <button onClick={() => {
            setNum((preN) => preN + 1)// 传入函数,在事件完成之后统一运行 -> 1
            setNum((preN) => preN + 1)// -> 2
        }}></button>
      </div>
    </div>
  )
}

image.png