【问题标题】:Why useRef value dynamically updates when it is an integer but stores the previous value when it is a string?为什么 useRef 值在它是整数时会动态更新,但在它是字符串时会存储先前的值?
【发布时间】:2021-10-29 18:36:32
【问题描述】:

我刚刚学习了 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] 的用途是什么。无论有没有它,我都会得到相同的结果和渲染计数。

【问题讨论】:

  • [name] in useEffect 是一个依赖项。在此数组中,您声明了一个依赖项列表,并且当其中至少一个更改时,执行 useEffect 中的代码。代码也在第一次渲染时运行。因此,每次在输入文本中键入内容时,您都会更改 previousName.current。如果你不添加任何依赖,useEffect 将在每次组件重新渲染时运行。
  • @Antonio 能否解释一下为什么 perviousName.current 总是在名称后面加一个字母?就像我输入'abcd'.. name = 'abcd' 但是 perviousName.current = 'abc'?它在 useEffect 里面,所以当名称更新时为什么 useRef 不是?

标签: reactjs use-ref


【解决方案1】:

在您的示例中,previousName 落后了一步,因为当您更改 name 状态时,组件将重新渲染,调用 useEffect 并更新 previousName,但最后的更改不会导致新的渲染( useRef 与 useState 不同,组件不会重新渲染),因此您会看到 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>
  );

【讨论】:

  • 我现在明白了,谢谢。
  • 如果您可以接受并且认为它可能对其他人有帮助,请考虑将其接受。
猜你喜欢
  • 1970-01-01
  • 2021-04-23
  • 1970-01-01
  • 2013-09-29
  • 2016-04-23
  • 2017-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多