在 MS Edge 中的 React 应用程序中调用 setState 后输入未更新
Input doesn't get updated after calling setState in React app in MS Edge
我创建了一个 React 应用程序。它在 IE、Opera、Chrome、FF 中按预期工作。我在状态更新后在 Edge 中渲染一个组件时遇到问题。对于 Chrome,我无法帮助自己使用 React Devtools,因为它在那里一切正常。
我的组件是两个输入字段的组合。一个是数字输入,可以由用户操作,另一个显示相同的数字值,但格式为货币字符串。当用户单击该字段时,具有格式化值的字段隐藏并显示非格式化输入字段。当用户离开可编辑输入时,之前隐藏的输入再次显示。
因为每次触发 onchange
事件时状态都会改变,我希望其他输入也会在每个 onchange
上更新。
这是因为它被隐藏了吗?
这是代码,我尽量简化了它:
class MasterComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
Rows: [
{ Id: 1, Name: 'Row 1', Price: 11 },
{ Id: 2, Name: 'Row 2', Price: 21 },
{ Id: 3, Name: 'Row 3', Price: 13 }
]
}
this.changeObjectValue = this.changeObjectValue.bind(this);
}
render() {
return <MCVE changeObjectValue={this.changeObjectValue} rows={this.state.Rows}></MCVE>
}
changeObjectValue(rowId, propertyName, value) {
// define which list user wants to change
let list = this.state['Rows'];
let changedList = [];
// change value
list.forEach(element => {
if (element.Id == rowId) {
element[propertyName] = value;
}
changedList.push(element);
});
// dynamically set objct name frmo parameters
this.setState({ Rows: changedList });
}
}
class MCVE extends React.Component {
render() {
return <table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{this.props.rows.map((r, index) =>
<tr key={r.Id}>
<td>
<input readOnly value={r.Id}></input>
</td>
<td><input name="Name" onChange={event => this.changeInput(event, r.Id)} value={r.Name}></input></td>
<td>
<input name="Price" className="edit" type="hidden" onBlur={event => toggleEditDisplay(event)} onChange={event => this.changeInput(event, r.Id)} value={r.Price}></input>
<input name="Price" className="display" readOnly onClick={event => toggleEditDisplay(event)} value={formatMoney(r.Price)}></input>
</td>
</tr>
)}
</tbody>
</table>
;
}
changeInput(event, rowId) {
let propertyName = event.target.name;
this.props.changeObjectValue(
rowId,
propertyName,
event.target.value);
}
}
function toggleEditDisplay(event) {
let el = event.target;
// if has class 'edit' else has class 'display'
if (el.className.split(/\s+/).filter(e => e == 'edit').length > 0) {
let elToToggle = el.parentElement.getElementsByClassName('display')[0];
el.type = "hidden";
elToToggle.type = "text";
}
else {
let elToToggle = el.parentElement.getElementsByClassName('edit')[0];
el.type = "hidden";
elToToggle.type = "number";
}
}
function formatMoney(amount, decimalCount = 2, decimal = ",", thousands = ".", currencySymbol = '€', ignoreCurrencySymbol = false) {
try {
decimalCount = Math.abs(decimalCount);
decimalCount = isNaN(decimalCount) ? 2 : decimalCount;
const negativeSign = amount < 0 ? "-" : "";
let i = parseInt(amount = Math.abs(Number(amount) || 0).toFixed(decimalCount)).toString();
let j = (i.length > 3) ? i.length % 3 : 0;
return negativeSign + (j ? i.substr(0, j) + thousands : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, "" + thousands) + (decimalCount ? decimal + Math.abs(amount - i).toFixed(decimalCount).slice(2) : "") + (ignoreCurrencySymbol ? "" : currencySymbol);
} catch (e) {
console.log(e)
}
};
ReactDOM.render(<MasterComponent />, document.getElementById('app'));
最小值HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="app"></div>
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<script src="reactScript.js"></script>
</body>
</html>
经测试,问题似乎与type="hidden"
有关,我们可以修改代码,使用CSS显示属性来隐藏或显示输入元素。请检查以下步骤:
- 从第一个输入的 TexBox 中删除 'type="hidden"'。
在index.css文件中添加如下css样式:
.edit{
display:none;
}
修改toggleEditDisplay函数:
function toggleEditDisplay(event) {
let el = event.target;
// if has class 'edit' else has class 'display'
if (el.className.split(/\s+/).filter(e => e == 'edit').length > 0) {
let elToToggle = el.parentElement.getElementsByClassName('display')[0];
el.style.display ='none';
elToToggle.type = "text";
elToToggle.style.display ='block';
}
else {
let elToToggle = el.parentElement.children[0];
//el.type = "hidden";
el.style.display ='none';
elToToggle.type = "number";
elToToggle.style.display ='block';
}
el.focus();
}
Edge浏览器中的结果如下:
我创建了一个 React 应用程序。它在 IE、Opera、Chrome、FF 中按预期工作。我在状态更新后在 Edge 中渲染一个组件时遇到问题。对于 Chrome,我无法帮助自己使用 React Devtools,因为它在那里一切正常。
我的组件是两个输入字段的组合。一个是数字输入,可以由用户操作,另一个显示相同的数字值,但格式为货币字符串。当用户单击该字段时,具有格式化值的字段隐藏并显示非格式化输入字段。当用户离开可编辑输入时,之前隐藏的输入再次显示。
因为每次触发 onchange
事件时状态都会改变,我希望其他输入也会在每个 onchange
上更新。
这是因为它被隐藏了吗?
这是代码,我尽量简化了它:
class MasterComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
Rows: [
{ Id: 1, Name: 'Row 1', Price: 11 },
{ Id: 2, Name: 'Row 2', Price: 21 },
{ Id: 3, Name: 'Row 3', Price: 13 }
]
}
this.changeObjectValue = this.changeObjectValue.bind(this);
}
render() {
return <MCVE changeObjectValue={this.changeObjectValue} rows={this.state.Rows}></MCVE>
}
changeObjectValue(rowId, propertyName, value) {
// define which list user wants to change
let list = this.state['Rows'];
let changedList = [];
// change value
list.forEach(element => {
if (element.Id == rowId) {
element[propertyName] = value;
}
changedList.push(element);
});
// dynamically set objct name frmo parameters
this.setState({ Rows: changedList });
}
}
class MCVE extends React.Component {
render() {
return <table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{this.props.rows.map((r, index) =>
<tr key={r.Id}>
<td>
<input readOnly value={r.Id}></input>
</td>
<td><input name="Name" onChange={event => this.changeInput(event, r.Id)} value={r.Name}></input></td>
<td>
<input name="Price" className="edit" type="hidden" onBlur={event => toggleEditDisplay(event)} onChange={event => this.changeInput(event, r.Id)} value={r.Price}></input>
<input name="Price" className="display" readOnly onClick={event => toggleEditDisplay(event)} value={formatMoney(r.Price)}></input>
</td>
</tr>
)}
</tbody>
</table>
;
}
changeInput(event, rowId) {
let propertyName = event.target.name;
this.props.changeObjectValue(
rowId,
propertyName,
event.target.value);
}
}
function toggleEditDisplay(event) {
let el = event.target;
// if has class 'edit' else has class 'display'
if (el.className.split(/\s+/).filter(e => e == 'edit').length > 0) {
let elToToggle = el.parentElement.getElementsByClassName('display')[0];
el.type = "hidden";
elToToggle.type = "text";
}
else {
let elToToggle = el.parentElement.getElementsByClassName('edit')[0];
el.type = "hidden";
elToToggle.type = "number";
}
}
function formatMoney(amount, decimalCount = 2, decimal = ",", thousands = ".", currencySymbol = '€', ignoreCurrencySymbol = false) {
try {
decimalCount = Math.abs(decimalCount);
decimalCount = isNaN(decimalCount) ? 2 : decimalCount;
const negativeSign = amount < 0 ? "-" : "";
let i = parseInt(amount = Math.abs(Number(amount) || 0).toFixed(decimalCount)).toString();
let j = (i.length > 3) ? i.length % 3 : 0;
return negativeSign + (j ? i.substr(0, j) + thousands : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, "" + thousands) + (decimalCount ? decimal + Math.abs(amount - i).toFixed(decimalCount).slice(2) : "") + (ignoreCurrencySymbol ? "" : currencySymbol);
} catch (e) {
console.log(e)
}
};
ReactDOM.render(<MasterComponent />, document.getElementById('app'));
最小值HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="app"></div>
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<script src="reactScript.js"></script>
</body>
</html>
经测试,问题似乎与type="hidden"
有关,我们可以修改代码,使用CSS显示属性来隐藏或显示输入元素。请检查以下步骤:
- 从第一个输入的 TexBox 中删除 'type="hidden"'。
在index.css文件中添加如下css样式:
.edit{ display:none; }
修改toggleEditDisplay函数:
function toggleEditDisplay(event) { let el = event.target; // if has class 'edit' else has class 'display' if (el.className.split(/\s+/).filter(e => e == 'edit').length > 0) { let elToToggle = el.parentElement.getElementsByClassName('display')[0]; el.style.display ='none'; elToToggle.type = "text"; elToToggle.style.display ='block'; } else { let elToToggle = el.parentElement.children[0]; //el.type = "hidden"; el.style.display ='none'; elToToggle.type = "number"; elToToggle.style.display ='block'; } el.focus(); }
Edge浏览器中的结果如下: