【问题标题】:Listening for useState default value event监听 useState 默认值事件
【发布时间】:2019-11-02 06:54:17
【问题描述】:

我想知道如何在函数中获取更新后的labelRef,即inputBlur()

import React, { useState, useRef, useEffect } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [inputValue, setInputValue] = useState("Type...");
  const [labelWidth, setLabelWidth] = useState();
  const labelRef = useRef();

  const inputChange = e => {
    setInputValue(e.target.value);
    setLabelWidth(labelRef.current.offsetWidth);
  };

  const inputBlur = e => {
    const trimmed = e.target.value.trim();
    if (trimmed) {
      setInputValue(trimmed);
    } else {
      setInputValue("Type...");
    }
    setLabelWidth(labelRef.current.offsetWidth);
  };

  useEffect(() => {
    setLabelWidth(labelRef.current.offsetWidth);
  }, []);
  return (
    <div className="App">
      <p>Type below to see if input and div is the same width</p>
      <div ref={labelRef}>{inputValue}</div>
      <br />
      <input
        value={inputValue}
        onChange={e => inputChange(e)}
        onBlur={e => inputBlur(e)}
        style={{ width: `${labelWidth}px` }}
      />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

为了稍微解释一下这个例子,有一个输入字段通过用相同的文本填充div 来改变其宽度。目前,当输入字段为空后跟onblur 事件时,它无法正常工作。输入字段应使用默认值useState 填充,"Type...",但输入字段宽度为 0。

我看到的问题是在inputBlur函数中,在触发setInputValue之后,labelRef.current.offsetWidth这行仍然反映了旧元素,因为它还没有重新渲染那个元素。

这里是这个例子的link to the codesandbox 来尝试复制这个问题。

我的问题来自于对 react hook 的流程缺乏了解。我需要在useState用默认值更新元素后捕获事件,然后计算宽度。

注意:我不希望输入在仍处于焦点时自动使用默认值填充空输入字段。必须在 onBlur() 事件中填写。

【问题讨论】:

  • 为什么你需要setLabelWidth 而不是仅仅使用引用style={{ width: `${labelRef.current.offsetWidth}px` }}
  • 我认为 labelRef 最初可以在 componentDidMount 中访问,就像在 useEffect 中一样。虽然我最初可以像您提到的那样得到labelRef,但labelRef.current 返回未定义。我的评价对吗?你能让它以这种方式工作吗?
  • 对,它需要是 labelRef.current?.offsetWidth 或一个很好的旧 labelRef.current &amp;&amp; labelRef.current.offsetWidth...

标签: reactjs input dom-events react-hooks


【解决方案1】:

不太确定我的问题是否正确,所以这就像一个假设。

根本原因:您在同一个地方调用setInputValuesetLabelWidth - 输入处理程序。但是setInputValue 只会在下次渲染时使用新值更新标签。所以它需要labelWidth 作为以前的值。

这不仅发生在您清空值时 - 您可能会看到输入时输入的宽度变化不一致。

分开useEffect:

  const inputBlur = e => {
    const trimmed = e.target.value;
    if (trimmed) {
      setInputValue(trimmed);
    } else {
      setInputValue("Type...");
    }
  };

  useEffect(() => {
    setLabelWidth(labelRef.current.offsetWidth);
  }, [inputValue])

【讨论】:

  • 奇怪的是,我在提供的代码沙箱中遇到了空格问题,但在我的实际项目中没有问题。
  • 我认为这是正确的原因是因为从 onChangeonBlur 事件设置状态会导致重新渲染,这实际上会在 inputValue 更改时触发 useEffect。由于我们在componentDidUpdate 之后访问ref,因此宽度状态设置正确。谢谢!
【解决方案2】:

inBlur 函数中,您正在使用 div 的当前 offsetWidth 更新labeWidth,在空输入后跟 onBlur 事件后始终为 0。改为:setLabelWidth(labelWidth);

另一种方法是将ref={labelRef} 移动到输入元素:&lt;input ref={labelRef} /&gt;。见官方docs

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 2015-06-23
    • 2020-06-25
    • 2011-10-07
    相关资源
    最近更新 更多