为何useRef计数显示当前值,文本却呈现旧值?
useRef更新与渲染时机的困惑
我对useRef的功能有个疑问:我们知道useEffect会在渲染完成后执行更新,且useRef的值更新不会触发重渲染,所以它的值更新通常会滞后一个周期,DOM里显示的一般是旧值,这也是useRef的典型特性。但下面的示例中,计数却能正常显示当前值,没有滞后,这是为什么?
import React from "react"; import "./App.css"; import { useEffect, useState, useRef } from "react"; function App(){ const count = useRef(0); const text = useRef(""); const [inputValue, setInputValue] = useState(""); useEffect(() => { text.current = inputValue; count.current = count.current + 1; }); return ( <> <input type="text" value={inputValue} onChange={(e)=>setInputValue(e.target.value)} /> <h1>Render Count: {count.current}</h1> {/* 输入后显示1 */} <h1>{text.current}</h1> {/* 输入后显示"" */} </> ); }
当在输入框输入字母"A"后,count.current从0变为1并显示1,但text.current却显示旧值""而非"A"。按道理计数应该滞后一个周期,要等到第二次重渲染后才显示1,为什么实际不是这样?
拆解执行流程,搞懂差异原因
我们一步步梳理代码的执行顺序:
1. 组件初始渲染
count.current初始值0,text.current初始值"",inputValue初始值""- React渲染DOM:输入框为空,
Render Count显示0,下方标题为空 - 渲染完成后执行
useEffect(无依赖项,每次渲染后都触发):text.current = inputValue→ 赋值为空字符串count.current = count.current +1→ 从0变成1
- 此时
count.current已是1,但useRef不会触发重渲染,所以DOM里的Render Count仍显示0
2. 输入"A"触发的流程
- 输入"A",
onChange调用setInputValue("A"),inputValue状态更新,触发组件第二次重渲染 - 渲染阶段:组件重新执行,此时读取的是上一次Effect更新后的
count.current(1),以及上一次Effect设置的text.current("") - React将这些内容更新到DOM:输入框显示"A",
Render Count显示1,下方标题显示"" - 渲染完成后执行本次
useEffect:text.current = inputValue→ 赋值为"A"count.current = count.current +1→ 从1变成2
- 此时
text.current已变成"A",但没有重渲染触发,DOM不会同步更新;count.current变成2,要等到下一次重渲染才会显示在页面上
总结
- 你看到
count.current显示1,不是因为它没有滞后,而是初始渲染后的Effect已经把它更新成1了,第二次渲染时直接读取了这个更新后的值。 text.current在输入后显示空,是因为第二次渲染阶段读取的是上一次Effect设置的旧值(空),本次Effect把它改成"A"的操作发生在渲染完成后,没有触发重渲染,所以DOM不会同步更新。
内容的提问来源于stack exchange,提问作者Kavya Jain
相关产品推荐
相关产品推荐

