React-useState

useState

useState是React的一个Hook函数,它可以在函数式组件中添加一个状态变量。

使用方式为

const [state, setState] = useState(initialState)

传入的参数是一个状态的初始值initialState

返回值是一个数组,数组中第一个值是当前的state,在首次渲染的时候为initialState。第二个值是用于更新当前state值的函数setState,并触发重新渲染。

注意事项:

  • useState 是一个 Hook,因此你只能在 组件的顶层 或自己的 Hook 中调用它。

在组件中的使用方式为

import { useState } from 'react';

function App() {
    const [count, setCount] = useState(0)
    const [msg, setMsg] = useState('msg')
}

set函数

set函数有两种使用方式

  • 直接给state赋予新的值

  • 传入一个可以根据先前的state来按照一定的逻辑更新state的函数

    setState(state => {
        return state + 1
    })
    

注意事项:

  • set函数只会在下一次渲染的时候更新状态变量state的值,也就是说如果在set函数之后读取状态变量state的值,那么只会读取到本次渲染的值,也就是未进行更新的值。

    // count = 1
    setCount(count + 1)
    console.log(count) // 1
    
  • 如果你提供的新值与当前 state 相同(由Object.is比较确定),React 将 跳过重新渲染该组件及其子组件

    • 对于基本数据类型,Object.is 可以直接判断出来二者是否相同。
    • 对于引用数据类型,Object.is 是根据引用地址进行判断的。
  • React 会 批量处理状态更新。它会在所有 事件处理函数运行 并调用其 set 函数后更新屏幕。这可以防止在单个事件期间多次重新渲染。也就是说React会把多次setState的更新合并到同一个。

多次更新state,效果却一样

// UseStateDemo.jsx
import { useState } from "react"

const UseStateDemo = () => {
  const [count, setCount] = useState(0)
  const [msg, setMsg] = useState('msg')

  const handleClick = () => {
    console.log('count', count)

    setCount(count + 1)
    console.log('first add', count)

    setCount(count + 1)
    console.log('second add', count)
  }

  return (
    <div>
      <div>{msg}-count: {count}</div>
      <div>
        <button onClick={handleClick}>add</button>
      </div>
    </div>
  )
}

export default UseStateDemo

在这里插入图片描述

会发现react把两次的更新合并到一起,所以每一次执行setCount的时候,组件内部的count其实并没有及时更新,所以count的值还为0。在第二次执行setCount的时候,也是在执行 count + 1 = 0 + 1 = 1。所以最终渲染出来的count为1

为了解决这个问题,我们就需要react执行批量按顺序更新,也就是setState需要根据上一次state的值来得到最新的state的值。所以就需要用到set函数的第二个用法。

import { useState } from "react"

const UseStateDemo = () => {
  ...

  const handleClick = () => {
    console.log('count', count)

    // setCount(count + 1)
    // console.log('first add', count)

    // setCount(count + 1)
    // console.log('second add', count)
    setCount(count => {
      console.log('first add', count)
      return count + 1
    })

    setCount(count => {
      console.log('second add', count)
      return count + 1
    })
    console.log('final-count', count)
  }

  return (
    ...
  )
}

export default UseStateDemo

在这里插入图片描述

实际上,采取第二种方式的时候,React会将更新的操作放在一个队列里面,然后,在下一次渲染期间,React将按照相同的顺序调用它们,并在事件处理函数的结尾去依次清空队列传入上一个值。

  1. 执行count => count + 1,接收count = 0为初始状态,返回count = 1为下一个状态;
  2. 执行count => count + 1,接收count = 1为初始状态,返回count = 2为下一个状态;

已经更新状态,但是日志仍然显示旧值

import { useState } from "react"

const UseStateDemo = () => {
  const [count, setCount] = useState(0)
  const [msg, setMsg] = useState('msg')

  const handleClick = () => {
    console.log('count', count)

    setCount(count + 1); // 请求使用 1 重新渲染
    console.log(count);  // 仍然是 0!

    let timer = setTimeout(() => {
      clearTimeout(timer)
      console.log('setTimeout', count); // 还是 0!
    }, 5000);
  }

  return (
    <div>
      <div>{msg}-count: {count}</div>
      <div>
        <button onClick={handleClick}>add</button>
      </div>
    </div>
  )
}

export default UseStateDemo

在这里插入图片描述

这是因为state表现如同一张快照,当触发setState的时候,就会触发一次渲染,而每一次渲染函数内部都拥有自己独立的 props 和 state。在上面代码中,触发setCount进入到第二张快照。但是这不影响已经运行的事件处理函数中的 count 状态变量。这个时候setTimeout拿到的 count 状态变量其实是第一张快照的值,也就是 0 。

为了解决这个问题,可以用一个新的变量来保存 count 状态变量更新后的值,并用这个新变量来执行后面的操作,再触发SetCount。

const nextCount = count + 1;
setCount(nextCount);

console.log(count);     // 0
console.log(nextCount); // 1
  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值