我遇到一个问题,在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
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>
);
}
}
答案 0 :(得分:1)
你不应该对州进行直接行动。
如果您正确使用setState
,则无需拨打forceUpdate
,setState
本身会要求重新申请该应用。
我会建议您bind
index
到deleteAccount
功能,而不是设置和检索事件中的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)
<input type="text" className="form-control" name='url' id={account.id} value={account.url} onChange={this.updateInputValue} defaultValue={account.url}/>