首页 > 解决方案 > 为什么 useRef 值在它是整数时会动态更新,但在它是字符串时会存储先前的值?

问题描述

我刚刚学习了 useRef 并且对它的实际工作方式感到困惑。例如,#1

function Ref() {
  const rerenderCount = useRef(0);

  useEffect(() => {
    rerenderCount.current = rerenderCount.current + 1;
  });

  return <div>{rerenderCount.current}</div>;
}

在这里,useRef 在下面的代码中给出了与 useState 相同的输出,#2

function State() {
  const [rerenderCount, setRerenderCount] = useState(0);

  useEffect(() => {
    setRerenderCount(prevCount => prevCount + 1);
  });

  return <div>{rerenderCount}</div>;
}

但是在这个#3 代码中,previousName.current 值总是显示前一个值。但它被设置为名称。

const [name, setName] = useState("");
  const previousName = useRef(null);

  useEffect(() => {
    previousName.current = name;
  }, [name]);

  return (
    <div className="App">
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <div>
        My name is {name} and it used to be {previousName.current}
      </div>
    </div>
  );

请有人解释为什么这个名字在整数按时更新的地方倒退了一步。另外,useEffect 中 [name] 的用途是什么。没有或没有它,我得到相同的结果和渲染计数。

标签: reactjsuse-ref

解决方案


在您的示例previousName中落后了一步,因为当您更改name组件重新渲染的状态时,会调用并previousName更新 useEffect 但最后一次更改不会导致新的渲染(useRef 不像 useState,组件不会重新渲染render),因此您会看到name正确更新但previousName具有与以前相同的值,即使其值已更改。这是因为previousName在后续渲染过程中由于状态的变化而发生了变化。要看到它的变化,需要额外的渲染。为了避免这种行为,您可以使用事件处理程序而不依赖 useEffect 挂钩。

const handleChange = (text: string) => {
    setName(text);
    previousName.current = text;
  };

  return (
    <div className="App">
      <input value={name} onChange={(e) => handleChange(e.target.value)} />
      <div>
        My name is {name} and it used to be {previousName.current}
      </div>
    </div>
  );

推荐阅读