对文本作出反应输入字段,在重新呈现组件后,输入仍保持旧值

时间:2017-02-15 12:54:10

标签: reactjs dom

我遇到一个问题,在React中,在我使用this.forceUpdate()之后,组件DOM会更新,但DOM(输入)仍然保留旧值。就像在图片中一样,我首先添加四行输入,并注意每个num上的数字,然后我删除第一行,DOM应该保留最后三行(2,3,4),但是结果是组件保留前三行(1,2,3)。

我检查页面,发现组件确实删除了第一行(编号为1的行),但DOM仍显示前三行,就像我删除第四行一样。

有人可以告诉我原因吗?谢谢!

Modal with four rows of input before delete

Modal with three rows of input after delete

detail explain

import React  from 'react'
import Button from 'react-bootstrap/lib/Button'
import Modal from 'react-bootstrap/lib/Modal'


export default class AddAccountModal extends React.Component{

  constructor(props) {
    super(props)
    this.state = {
      newAccount: [{source: '', url: '', name: ''}],
    }

    this.getState = this.getState.bind(this);
    this.addMoreAccount = this.addMoreAccount.bind(this);
    this.updateInputValue = this.updateInputValue.bind(this);
    this.deleteAccount = this.deleteAccount.bind(this);
  }


  getState(){
    return this.state
  }

  updateInputValue(event){
    this.state.newAccount[event.target.id][event.target.name] = event.target.value
  }

  deleteAccount(event){
    console.log(event.target.id)
    this.state.newAccount.splice(event.target.id,1)
    console.log(this.state.newAccount)
    this.forceUpdate()
  }

  addMoreAccount(){
    this.state.newAccount.push({source: '', url: '', name: ''})
    console.log(this.getState()['newAccount'])
    this.forceUpdate()
  }

  render(){
    return (
      <Modal {...this.props}
             bsSize="large"
             aria-labelledby="contained-modal-title-lg">
        <Modal.Header>
          <Modal.Title id="contained-modal-title-lg">
            Add New Account
            <Button className="pull-right" onClick={this.props.hideModal}>X</Button>
          </Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <div className="row">
            <table className="table table-striped">
              <thead><th>Account source</th><th>Account URL</th><th>Account name</th><th>Delete</th></thead>
              <tbody>
                {
                  this.state.newAccount.map(
                    (account,index)=>{return <tr>
                      {/*<td><input type="text" class="form-control" name='source' id={index} onChange={this.updateInputValue} defaultValue={account.source}/></td>*/}
                      <td><input type="text" class="form-control" name='source' id={index} onChange={this.updateInputValue} ref={(input)=>{account.source=input}}/></td>
                      <td><input type="text" class="form-control" name='url' id={index} onChange={this.updateInputValue} defaultValue={account.url}/></td>
                      <td><input type="text" class="form-control" name='name' id={index} onChange={this.updateInputValue} defaultValue={account.name}/></td>
                      <td><i className="fa fa-trash" aria-hidden="true" id={index} onClick={this.deleteAccount}></i></td>
                    </tr>})
                }
                <tr><td></td><td><button onClick={ this.addMoreAccount }>+</button></td><td></td></tr>
              </tbody>
            </table>
          </div>
        </Modal.Body>
        <Modal.Footer>
          <Button onClick={this.props.hideModal}>Close</Button>
        </Modal.Footer>
      </Modal>
    );
  }

}

2 个答案:

答案 0 :(得分:1)

你不应该对州进行直接行动。

如果您正确使用setState,则无需拨打forceUpdatesetState本身会要求重新申请该应用。

我会建议您bind indexdeleteAccount功能,而不是设置和检索事件中的ID。

为了正确改变状态,你需要可以在一个临时数组中克隆状态变量并更改它然后设置状态,如

deleteAccount(id){
    var newAccount = [...this.state.newAccount];
    newAccount.splice(id,1);
    this.setState({newAccount}, () => {console.log(this.state.newAccount)});
  } 

我假设你的地图函数中的额外}

之后
 <td><i className="fa fa-trash" aria-hidden="true" id={index} onClick={this.deleteAccount}></i></td>
                </tr>}    <------ here

是原始代码中没有的拼写错误。如果它在那里你需要删除它。

同样当你设置State时,它不会立即变异,因此如果你想在使用setState回调之后立即记录它,就像我在下面的代码中所使用的那样

this.setState({newAccount}, () => {console.log(this.state.newAccount)});

完整代码应如下所示

import React  from 'react'
import Button from 'react-bootstrap/lib/Button'
import Modal from 'react-bootstrap/lib/Modal'


export default class AddAccountModal extends React.Component{

  constructor(props) {
    super(props)
    this.state = {
      newAccount: [{source: '', url: '', name: ''}],
    }

    this.getState = this.getState.bind(this);
    this.addMoreAccount = this.addMoreAccount.bind(this);
    this.updateInputValue = this.updateInputValue.bind(this);
    this.deleteAccount = this.deleteAccount.bind(this);
  }


  getState(){
    return this.state
  }

  updateInputValue(event){
    var newAccount = [...this.state.newAccount];
    newAccount[event.target.id][event.target.name] = event.target.value;
    this.setState({newAccount});
  }

  deleteAccount(id){
    var newAccount = [...this.state.newAccount];
    newAccount.splice(id,1);
    this.setState({newAccount}, () => {console.log(this.state.newAccount)});
  } 

  addMoreAccount(){
    var newAccount = [...this.state.newAccount];
    newAccount.push({source: '', url: '', name: ''})
    this.setState({newAccount}, () => {console.log(this.state.newAccount)})

  }

  render(){
    return (
      <Modal {...this.props}
             bsSize="large"
             aria-labelledby="contained-modal-title-lg">
        <Modal.Header>
          <Modal.Title id="contained-modal-title-lg">
            Add New Account
            <Button className="pull-right" onClick={this.props.hideModal}>X</Button>
          </Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <div className="row">
            <table className="table table-striped">
              <thead><th>Account source</th><th>Account URL</th><th>Account name</th><th>Delete</th></thead>
              <tbody>
                {
                  this.state.newAccount.map(
                    (account,index)=>{return <tr>
                      {/*<td><input type="text" class="form-control" name='source' id={index} onChange={this.updateInputValue} defaultValue={account.source}/></td>*/}
                      <td><input type="text" class="form-control" name='source' id={index} onChange={this.updateInputValue} ref={(input, index)=>{account.source=input}}/></td>
                      <td><input type="text" class="form-control" name='url' id={index} onChange={this.updateInputValue} defaultValue={account.url}/></td>
                      <td><input type="text" class="form-control" name='name' id={index} onChange={this.updateInputValue} defaultValue={account.name}/></td>
                      <td><i className="fa fa-trash" aria-hidden="true" id={index} onClick={this.deleteAccount.bind(this, index)}></i></td>
                    </tr>)
                }
                <tr><td></td><td><button onClick={ this.addMoreAccount }>+</button></td><td></td></tr>
              </tbody>
            </table>
          </div>
        </Modal.Body>
        <Modal.Footer>
          <Button onClick={this.props.hideModal}>Close</Button>
        </Modal.Footer>
      </Modal>
    );
  }

}

答案 1 :(得分:0)

每个人,我犯了一个愚蠢的错误,我应该为每个输入添加“value =”。虽然我仍然不知道如何在输入中添加“value =”。

<input type="text" className="form-control" name='url' id={account.id} value={account.url} onChange={this.updateInputValue} defaultValue={account.url}/>