useState与useRef

useState

  • react中一般使用useState方法为,初始化值为second,设置first的方法为setfirst。

    const [first, setfirst] = useState(second)
  • 一般情况下使用不会有什么问题,但是在你刚设置完状态后不能立刻使用该状态,原因是setState是异步执行的,何为异步执行?javascript为单线程,意思是只能自上而下顺序执行,如果某一环节出现问题,之后的也不会执行,所以javascript引入了异步执行操作。

    • js异步执行机制:

      • 首先判断该任务是同步还是异步,同步进入主线程顺序执行,异步的进入Event table

      • 异步任务在Event table中注册函数,然后被推入Event queue

      • 当主线程执行完所有的同步任务空闲之后,才去Event queue中查看是否有可执行的异步任务,如果有,就推入到主线程中执行

  • 由于setState是异步的,所以下面这段代码点击重置后不会立刻获得默认列表,但是第二次点击会获得默认列表,显然这是不符合预期的,所以应该怎么解决呢?

    const fun = () => {
    const [first, setfirst] = useState(second)
    //页面加载时,获取列表并展示
    useEffect(() => {
    getList()
    } , [])
    //搜索就是通过传入不同参数获得不同的结果列表
    const getList = () => {
    //发送请求,获取数据展现到页面上
    .......
    }
    //重置按钮就是将输入框置为空,然后获取默认列表
    const reset = () => {
    setfirst('')
    getList()
    }
    return (
    <React.Fragment>
    <div>
    <input type = "text" value = "{first}"/>
    <button onclick = {getList}>搜索</button>
    <button onclick = {reset}>重置</button>
    </div>
    </React.Fragment>
    )
    }

useRef

  • 上述的问题可以通过useRef来解决,使用方式如下,这种方式就可以实现点击reset后,清空输入框的值,并获取默认列表展示。
const fun = () => {
//使用useref定义状态
const first = useRef('')
//页面加载时,获取列表并展示
useEffect(() => {
getList()
} , [])

const getList = () => {
.......
}

const reset = () => {
//通过current.value来改变值
first.current.value = ''
getList()
}
return (
<React.Fragment>
<div>
//input通过ref绑定
<input type = "text" ref = {first}/>
<button onclick = {getList}>搜索</button>
<button onclick = {reset}>重置</button>
</div>
</React.Fragment>
)
}

两者区别

  • 受控组件与非受控组件
    • 受控组件:类似于useState这种,将组件的值放入state中进行维护,所以要访问组件的值,直接在state中进行读取,不必获取对应组件了,设置组件的值也要通过setState进行设置,整个过程就是组件的状态与维护。
    • 非受控组件:react本身并没有维护组件的值,想要获取组件的值,通过ref获取组件,然后通过ref获取或者设置组件的值,随取随用,且设置值后立即生效。
  • 由于useRef设置值是同步的,所以会立即生效。

问题记录

  • 在使用antd的Input输入框组件,通过useRef获取和设置组件的值,获取值的方式:first.current.input.value,设置值的方式:first.current.input.value = ‘’,类似于上面的例子,使用antd的input框点击重置后,有一瞬间清空了input,但是马上又恢复了之前input框输入的值,检查之后,感觉代码没什么问题,可能是antd的BUG吧。

总结

  1. 遇到问题:就是想点击reset后,清空输入框,并发送请求,展示默认的列表,
    1. 刚开始使用受控组件useState,但是由于是异步更改状态的,所以不行
    2. 后来使用非受控组件useRef,但是由于使用的antd,会有bug,也不行,如果使用html原生的,就没有问题
    3. 最后先使用受控组件:useState,input绑定的是useState的值,定义一个非受控组件useRef,使用useEffect,监测useState的值,当他的值改变,就将他的值赋给useRef所定义的那个变量。在发送请求的getList函数中读取useRef所定义的值即可。

Author: Yang Wa
Link: https://blog.wxywxy.cn/2022/09/20/useState与useRef/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.