深入学习useState

233 阅读2分钟

useState的基本使用

const [state,setState]=useState(initValue);
  • useState函数接收一个初始化参数initialState,其返回值用数组解构出两个参数:state和setState。

  • 在初始化渲染期间,返回的状态 (state) 与传入的第一个参数 (initialState) 值相同。

  • setState 函数用于更新 state。它接收一个新的 state 值并将组件的一次重新渲染加入队列。

  • 在后续的重新渲染中,useState 返回的第一个值将始终是更新后最新的 state。

修改state值

可以分为两种情况修改,一种是直接更新,一种是函数调用更新,具体使用如下

直接修改

setState(newState)

调用函数修改

setState((preState)=>{return nextState})

以上两种方法的区别在于调用函数修改可在函数内部指定条件后在执行更新,如在函数添加定时器,条件判断等等

代码如下

import { useEffect, useState } from 'react'

function Counter () {
  const [count, setCount] = useState(0)

  useEffect(() => {
    console.log(count)
  }, [count])
  function handleClick () {
    setTimeout(() => {
      setCount(count + 1)
    }, 2000)
  }
  function handleClickFn () {
    setTimeout(() => {
      setCount((prevCount) => {
        return prevCount + 1
      })
    }, 2000)
  }
  return (
      <>
        Count: {count}
        <button onClick={handleClick}>+</button>
        <button onClick={handleClickFn}>+</button>
      </>
  )
}

export default Counter

来看看以下效果

image.png

image.png

结论

上述第一种方法执行,连续点击每次点击会触发定时器,2秒之后才能再次点击(类似节流)

第二种方法执行,连续点击触发每次点击不会触发定时器,会在2秒之后执行点击事件(时间戳节流)

useState缺点

usestate获取不到新值

import { Button } from 'antd-mobile'
import { useEffect, useState } from 'react'

function Counter () {
  const [fields, setfields] = useState([0])
  console.log(fields)

  function change () {
    setTimeout(() => {
      setfields([...fields, 1])
    }, 100)
    setTimeout(() => {
      setfields([...fields, 2])
    }, 500)
  }
  useEffect(() => {
  }, [fields])
  return <Button onClick={change}>change</Button>
}

export default Counter

上述代码按着正常逻辑会打印 [0,1,2],但是useState的特点就是异步回调拿不到新的值所以也就打印的是[0,2]

需求现在要打印成[0,1,2]

怎么解决这样的问题呢?

我们可以采取useRef配合使用代码如下

import { Button } from 'antd-mobile'
import { useEffect, useState, useRef } from 'react'

function Counter () {
  const [fields, setfields] = useState([0])
  const fieldsRef = useRef<number[]>([])
  console.log(fields)

  function change () {
    setTimeout(() => {
      setfields([...fieldsRef.current, 1])
    }, 100)
    setTimeout(() => {
      setfields([...fieldsRef.current, 2])
    }, 500)
  }
  useEffect(() => {
    fieldsRef.current = fields
  }, [fields])
  return <Button onClick={change}>change</Button>
}

export default Counter

还有一种方法 (不适用)

import { Button } from 'antd-mobile'
import { useEffect, useState } from 'react'

function Counter () {
  const [fields, setfields] = useState([0])
  console.log(fields)

  function change () {
    setTimeout(() => {
      setfields([...fields, 1])
    }, 100)
    setTimeout(() => {
      fields.push(1)
      setfields([...fields, 2])
    }, 500)
  }
  useEffect(() => {
  }, [fields])
  return <Button onClick={change}>change</Button>
}

export default Counter