You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 01:15:50