如果 HTML 元素在函数内部更新,则 React SetState 在第二次渲染之前无法工作
React SetState not working till second render if HTML element updated inside a function
我正在处理一个 useState 示例,我发现它在第二次渲染之前不起作用。第一次它保持默认值 0。
import React, { useState } from "react";
const MyState = () => {
const [age, setage] = useState(0);
function handleClick() {
var enteredAge = document.getElementById("txtAge").value;
if (enteredAge) {
setage(enteredAge);
if (enteredAge > 50) {
document.getElementById("lblResult").innerText = "Wow " + age + "! You're old, rest up!";
} else {
document.getElementById("lblResult").innerText = "Wow " + age + "! Young gun!";
}
}
}
return (
<div>
Enter Your Age:
<input type="text" id="txtAge" name="age" />
<button onClick={handleClick}> Check </button>
<label id="lblResult"></label>
</div>
);
};
export default MyState;
如果我执行类似以下操作,这在每个渲染器上都可以正常工作。但是如果我像上面显示的那样在函数内部使用 setState,那么 innerText 中的年龄仍然保持旧值。为什么会这样,正确的做法是什么?
<label id="lblResult">{age}</label>
你不应该直接改变 DOM 节点,因为反应维护 V-DOM 并且你对 lblresult
所做的改变将在 re-render 之后丢失。正确的方法是使用状态值并有条件地渲染数据。
import React, { useState } from 'react';
const MyState = () => {
const [age, setage] = useState(0);
function handleClick() {
var enteredAge = document.getElementById('txtAge').value;
if (enteredAge) {
setage(enteredAge);
}
}
return (
<div>
Enter Your Age:
<input type="text" id="txtAge" name="age" />
<button onClick={handleClick}> Check </button>
<label id="lblResult">
{age > 50
? `"Wow ${age}! You're old, rest up!`
: `Wow ${age}! Young gun!`}
</label>
</div>
);
};
export default MyState;
更新:
正如 Bjorn 提到的,您可以使用 refs
而不是 getElementById
来获取输入字段值。 Ref 是一个在 re-render 之间具有持久引用的对象,ref 的 current
属性 持有 DOM 节点。
import React, { useState, useRef } from 'react';
const MyState = () => {
const [age, setage] = useState(0);
const inputRef = useRef(null);
function handleClick() {
var enteredAge = inputRef.current.value;
if (enteredAge) {
setage(enteredAge);
}
}
return (
<div>
Enter Your Age:
<input type="text" id="txtAge" name="age" ref={inputRef} />
<button onClick={handleClick}> Check </button>
<label id="lblResult">
{age > 50
? `"Wow ${age}! You're old, rest up!`
: `Wow ${age}! Young gun!`}
</label>
</div>
);
};
export default MyState;
我正在处理一个 useState 示例,我发现它在第二次渲染之前不起作用。第一次它保持默认值 0。
import React, { useState } from "react";
const MyState = () => {
const [age, setage] = useState(0);
function handleClick() {
var enteredAge = document.getElementById("txtAge").value;
if (enteredAge) {
setage(enteredAge);
if (enteredAge > 50) {
document.getElementById("lblResult").innerText = "Wow " + age + "! You're old, rest up!";
} else {
document.getElementById("lblResult").innerText = "Wow " + age + "! Young gun!";
}
}
}
return (
<div>
Enter Your Age:
<input type="text" id="txtAge" name="age" />
<button onClick={handleClick}> Check </button>
<label id="lblResult"></label>
</div>
);
};
export default MyState;
如果我执行类似以下操作,这在每个渲染器上都可以正常工作。但是如果我像上面显示的那样在函数内部使用 setState,那么 innerText 中的年龄仍然保持旧值。为什么会这样,正确的做法是什么?
<label id="lblResult">{age}</label>
你不应该直接改变 DOM 节点,因为反应维护 V-DOM 并且你对 lblresult
所做的改变将在 re-render 之后丢失。正确的方法是使用状态值并有条件地渲染数据。
import React, { useState } from 'react';
const MyState = () => {
const [age, setage] = useState(0);
function handleClick() {
var enteredAge = document.getElementById('txtAge').value;
if (enteredAge) {
setage(enteredAge);
}
}
return (
<div>
Enter Your Age:
<input type="text" id="txtAge" name="age" />
<button onClick={handleClick}> Check </button>
<label id="lblResult">
{age > 50
? `"Wow ${age}! You're old, rest up!`
: `Wow ${age}! Young gun!`}
</label>
</div>
);
};
export default MyState;
更新:
正如 Bjorn 提到的,您可以使用 refs
而不是 getElementById
来获取输入字段值。 Ref 是一个在 re-render 之间具有持久引用的对象,ref 的 current
属性 持有 DOM 节点。
import React, { useState, useRef } from 'react';
const MyState = () => {
const [age, setage] = useState(0);
const inputRef = useRef(null);
function handleClick() {
var enteredAge = inputRef.current.value;
if (enteredAge) {
setage(enteredAge);
}
}
return (
<div>
Enter Your Age:
<input type="text" id="txtAge" name="age" ref={inputRef} />
<button onClick={handleClick}> Check </button>
<label id="lblResult">
{age > 50
? `"Wow ${age}! You're old, rest up!`
: `Wow ${age}! Young gun!`}
</label>
</div>
);
};
export default MyState;