在 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显示属性来隐藏或显示输入元素。请检查以下步骤:

  1. 从第一个输入的 TexBox 中删除 'type="hidden"'。
  2. 在index.css文件中添加如下css样式:

    .edit{
      display:none;
    }
    
  3. 修改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浏览器中的结果如下: