改变状态时输入值不更新
input value not updating when mutating state
在创建一个用于学习目的的小项目时,我遇到了输入值更新的问题。这是组件(我已尝试将其减少到最低限度)。
function TipSelector({selections, onTipChanged}: {selections: TipSelectorItem[], onTipChanged?:(tipPercent:number)=>void}) {
const [controls, setControls] = useState<any>([]);
const [tip, setTip] = useState<string>("0");
function customTipChanged(percent: string) {
setTip(percent);
}
//Build controls
function buildControls()
{
let controlList: any[] = [];
controlList.push(<input className={styles.input} value={tip.toString()} onChange={(event)=> {customTipChanged(event.target.value)}}></input>);
setControls(controlList);
}
useEffect(()=>{
console.log("TipSelector: useEffect");
buildControls();
return ()=> {
console.log("unmounts");
}
},[])
console.log("TipSelector: Render -> "+tip);
return (
<div className={styles.tipSelector}>
<span className={globalStyles.label}>Select Tip %</span>
<div className={styles.btnContainer}>
{
controls
}
</div>
</div>
);
}
如果我将输入的创建直接移动到 return() 语句中,值会正确更新。
您只调用了一次 buildControls
,而 <input ...
仅在那一次获得了它的值。
每当 React 重新渲染您的组件(因为例如某些状态更改)时,您的 {controls}
将告诉 React 使用旧值渲染原始 <input ...
。
我不确定为什么要将控件存储在状态变量中?没有必要这样做,正如您所注意到的,它使事情变得很复杂。您基本上也需要一个 renderControls()
函数,您可以将 {controls}
替换为。
我会将您的输入移出该组件,让它们在 TipSelector 之外管理自己的状态。
参见:
https://codesandbox.io/s/naughty-http-d38w9
例如:
import { useState, useEffect } from "react";
import CustomInput from "./Input";
function TipSelector({ selections, onTipChanged }) {
const [controls, setControls] = useState([]);
//Build controls
function buildControls() {
let controlList = [];
controlList.push(<CustomInput />);
controlList.push(<CustomInput />);
setControls(controlList);
}
useEffect(() => {
buildControls();
return () => {
console.log("unmounts");
};
}, []);
return (
<div>
<span>Select Tip %</span>
<div>{controls}</div>
</div>
);
}
export default TipSelector;
import { useState, useEffect } from "react";
function CustomInput() {
const [tip, setTip] = useState("0");
function customTipChanged(percent) {
setTip(percent);
}
return (
<input
value={tip.toString()}
onChange={(event) => {
customTipChanged(event.target.value);
}}
></input>
);
}
export default CustomInput;
在创建一个用于学习目的的小项目时,我遇到了输入值更新的问题。这是组件(我已尝试将其减少到最低限度)。
function TipSelector({selections, onTipChanged}: {selections: TipSelectorItem[], onTipChanged?:(tipPercent:number)=>void}) {
const [controls, setControls] = useState<any>([]);
const [tip, setTip] = useState<string>("0");
function customTipChanged(percent: string) {
setTip(percent);
}
//Build controls
function buildControls()
{
let controlList: any[] = [];
controlList.push(<input className={styles.input} value={tip.toString()} onChange={(event)=> {customTipChanged(event.target.value)}}></input>);
setControls(controlList);
}
useEffect(()=>{
console.log("TipSelector: useEffect");
buildControls();
return ()=> {
console.log("unmounts");
}
},[])
console.log("TipSelector: Render -> "+tip);
return (
<div className={styles.tipSelector}>
<span className={globalStyles.label}>Select Tip %</span>
<div className={styles.btnContainer}>
{
controls
}
</div>
</div>
);
}
如果我将输入的创建直接移动到 return() 语句中,值会正确更新。
您只调用了一次 buildControls
,而 <input ...
仅在那一次获得了它的值。
每当 React 重新渲染您的组件(因为例如某些状态更改)时,您的 {controls}
将告诉 React 使用旧值渲染原始 <input ...
。
我不确定为什么要将控件存储在状态变量中?没有必要这样做,正如您所注意到的,它使事情变得很复杂。您基本上也需要一个 renderControls()
函数,您可以将 {controls}
替换为。
我会将您的输入移出该组件,让它们在 TipSelector 之外管理自己的状态。
参见:
https://codesandbox.io/s/naughty-http-d38w9
例如:
import { useState, useEffect } from "react";
import CustomInput from "./Input";
function TipSelector({ selections, onTipChanged }) {
const [controls, setControls] = useState([]);
//Build controls
function buildControls() {
let controlList = [];
controlList.push(<CustomInput />);
controlList.push(<CustomInput />);
setControls(controlList);
}
useEffect(() => {
buildControls();
return () => {
console.log("unmounts");
};
}, []);
return (
<div>
<span>Select Tip %</span>
<div>{controls}</div>
</div>
);
}
export default TipSelector;
import { useState, useEffect } from "react";
function CustomInput() {
const [tip, setTip] = useState("0");
function customTipChanged(percent) {
setTip(percent);
}
return (
<input
value={tip.toString()}
onChange={(event) => {
customTipChanged(event.target.value);
}}
></input>
);
}
export default CustomInput;