我想知道如何在一个函数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
仍然反映了旧元素,因为它尚未重新渲染该元素。 / p>
这里是此示例的link to the codesandbox,尝试复制此问题。
我的问题来自缺乏对react hook流程的理解。在useState
用默认值更新元素之后,我需要捕获事件,然后计算宽度。
注意:我不希望输入在仍处于焦点状态时自动使用默认值填充空白输入字段。它必须在onBlur()
事件中填写。
答案 0 :(得分:1)
不确定我是否正确回答了您的问题,所以这就像一个假设。
根本原因:您在同一位置(输入处理程序)同时调用setInputValue
和setLabelWidth
。但是setInputValue
仅在下一次渲染时才用新值更新标签。因此,需要labelWidth
作为先前的值。
不仅在您清空值时会发生这种情况-您可能会发现输入时输入的宽度不一致。
将其分开useEffect
:
const inputBlur = e => {
const trimmed = e.target.value;
if (trimmed) {
setInputValue(trimmed);
} else {
setInputValue("Type...");
}
};
useEffect(() => {
setLabelWidth(labelRef.current.offsetWidth);
}, [inputValue])
答案 1 :(得分:0)
在inBlur
函数中,您要使用div的当前offsetWidth更新labeWidth
,该值在输入为空后会发生onBlur事件后始终为0。更改为此:setLabelWidth(labelWidth);
另一种方法是将ref={labelRef}
移动到输入元素<input ref={labelRef} />
。见官方docs