useState和useRef的小结

343 阅读3分钟

不会弹吉他的铁匠不是一名好铁匠!大家好,我是拿吉他的铁匠,码字不易,希望大家多多点赞。

这篇文章主要是用来整理React中的useState和useRef的使用以及使用场景;在React中,分为类组件和函数组件,类组件是有自己的状态以及生命周期,函数组件是没有状态和生命周期的,所以在函数组件中,可以使用React提供的use Hooks添加状态,以及模块生命周期;useState和useRef就是用来在函数组件中添加状态。

UseRef

声明状态:

首先是引入useState:

import React, { useState } from "react";
  • useState一次只能声明一个状态变量,这个状态变量可以是任意类型的;

  • useState接收一个参数作为初始值,会在第一次渲染的时候被使用;

  • useState返回一个数组,通常会以数组解构的方式使用:

    • const [count, setCount] = useState(0)
    • count 是状态变量;setCount是改变该状态变量的方法;

更新状态

传入固定值:

  • const addCount = () => { setCount(10) }

想要在旧值的基础上得到新值,可以使用函数的形式:

  • const addCount = () => { setCount(count => count + 1) }

每一次更新状态,都会触发render重新渲染当前的组件;因此在涉及到对组件的操作时,使用useState是非常合适的;

注意点

  • useState()的异步性:

    • 在useState()更新状态后,马上获取state的值,会发现获取的不是最新值;这是因为React更新state的值是异步更新的:
    
    const addCount = () => {
      setCount(count => count + 1) // 3
      submit()
    }
    
    const submit = () => {
      console.log(count) // 2
    }
    

    正如上面的更新状态,页面上更新为3,但是获取count还是上次的旧值;所以想要马上使用state的最新值,useState()显然不能满足我们的需求;

  • 在顶层调用useState;

  • useState()不能在类组件中使用;

  • 不能在条件,循环,内嵌方法中使用useState,因为React依赖于useState函数被调用的顺序来获取特定变量的正确值;

useRef

获取DOM元素或者组件实例

 // 引入
import React, { useState, useRef } from "react"
 // 声明
const domRef = useRef(null)
// 赋值给DOM元素的ref属性
 <button onClick={addCount} ref={domRef}>改变</button>
// 使用
  const addCount = () => {
    console.log(domRef.current.innerHTML)
  }

这是useRef()的传统用法,通过对象的current属性就能获取到DOM元素;

获取状态的最新值

上面useState()无法获取最新值,在这里可以通过useRef()来解决这个棘手的问题;

useRef()返回一个可变Ref对象,包含一个current属性,返回的ref对象在整个生命周期内保持不变;

可以改变ref对象的current属性,不会触发组件的重新渲染;

通过ref对象的current属性获取变量的最新值;

  const countRef = useRef(0)
  
  
  const addCount = () => {
    let d = Math.random()
    setCount(d)
    countRef.current = d
    submit()
  }

  const submit = () => {
    console.log(countRef.current)
  }

在变量每次更新的时候,将最新的变量值保存在countRef的current属性中,在submit函数中就能得到变量的最新值;

上面代码是直接将传值保存在current属性中,现在不传值,想要实时获取setCount变化的值,又该怎么做呢?

import React, { useState, useRef, useEffect } from "react"

const countRef = useRef(0)

  useEffect(() => {
    countRef.current = count
  }, [count])

  const addCount = () => {
    setCount(d => d + 1)
     // countRef.current = count 这里保存的仍然是旧值,不正确
    // 这里非常重要
    setTimeout(submit, 0)
  }

  const submit = () => {
    console.log(countRef.current)
  }

上面的案例中,是count每次点击加1,还在addCount中保存到current,保存的是旧值,并不是最新值;这里就用到useEffect;

useEffect相当于类组件的生命周期钩子,会监听第二个参数值的变化,一旦监听到变化,就会执行回调;

上述的案例的步骤如下:

  • setCount会更新count值的变化,会触发render重新渲染组件;
  • useEffect()钩子监听到count值的变化,会将当前最新值保存在ref对象的current属性上;
  • 使用定时器来调用submit方法,这样也将submit转变为异步调用,确保在useEffect()执行完毕后获取到最新值;

所以简单总结一下:

  • 涉及到组件渲染更新可以使用useState();
  • 涉及到实时获取最新值,可以使用useRef();