I am not sure if it´s a react issue or not but I am struggling a lot with this issue. I tried to create just a simple example to post out of my project:
There are four buttons on the example.
To reproduce the problem press each of the first three buttons to create a text input from and enter a value. For example enter 100 into the first one, 200 into the second and 300 into the third. Now press the fourth button to remove the first input.
It should keep the second and third with their respective values, 200 and 300, but instead it´s showing 100 in the second and 200 in the third.
This code is the same as it is on CodePen, it just didn't allow the link to be posted without this.
class ButtonComponent extends React.Component {
constructor(props) {
super(props);
this.state = {filtersArr:[]}
this.addButtons = this.addButtons.bind(this);
this.removeButtons = this.removeButtons.bind(this);
this.getInput = this.getInput.bind(this);
this.onChangeHandler = this.onChangeHandler.bind(this);
}
addButtons(e){
let tempArr = this.state.filtersArr;
tempArr.push({p:this.getInput(e.target.id), id:e.target.id});
this.setState({filtersArr:tempArr});
}
removeButtons(e){
console.log(e.target.id);
let newArr = this.state.filtersArr.filter((filter)=>{
return (filter.id !=='FirstButton')
})
this.setState({filtersArr:newArr});
}
onChangeHandler(e){
console.log(e.target.value);
}
getInput(id){
return (
<div>
<h6>{id}</h6>
<input
id="min"
type="text"
placeholder="min"
onChange={this.onChangeHandler}/>
</div>
)
}
render() {
let styles = {
display:'inline-block'
}
return (
<div>
<p>Add three buttons and enter the number in each input, and remove amt.</p>
<button id="FirstButton" onClick={this.addButtons}>FirstButton</button>
<button id="SecondButton" onClick={this.addButtons}>SecondButton</button>
<button id="ThirdButton" onClick={this.addButtons}>ThirdButton</button>
<button id="FirstButton" onClick={this.removeButtons}>Remove firstButton</button>
<ul>
{this.state.filtersArr.map((filter, index)=>{
return <li style={styles} key={index}>{filterp}</li>
})
}
</ul>
</div>
);
}
}
ReactDOM.render(
<ButtonComponent/>,
document.getElementById('root')
);
I am not sure if it´s a react issue or not but I am struggling a lot with this issue. I tried to create just a simple example to post out of my project:
https://codepen.io/as3script/pen/VMbNdz?editors=1111
There are four buttons on the example.
To reproduce the problem press each of the first three buttons to create a text input from and enter a value. For example enter 100 into the first one, 200 into the second and 300 into the third. Now press the fourth button to remove the first input.
It should keep the second and third with their respective values, 200 and 300, but instead it´s showing 100 in the second and 200 in the third.
This code is the same as it is on CodePen, it just didn't allow the link to be posted without this.
class ButtonComponent extends React.Component {
constructor(props) {
super(props);
this.state = {filtersArr:[]}
this.addButtons = this.addButtons.bind(this);
this.removeButtons = this.removeButtons.bind(this);
this.getInput = this.getInput.bind(this);
this.onChangeHandler = this.onChangeHandler.bind(this);
}
addButtons(e){
let tempArr = this.state.filtersArr;
tempArr.push({p:this.getInput(e.target.id), id:e.target.id});
this.setState({filtersArr:tempArr});
}
removeButtons(e){
console.log(e.target.id);
let newArr = this.state.filtersArr.filter((filter)=>{
return (filter.id !=='FirstButton')
})
this.setState({filtersArr:newArr});
}
onChangeHandler(e){
console.log(e.target.value);
}
getInput(id){
return (
<div>
<h6>{id}</h6>
<input
id="min"
type="text"
placeholder="min"
onChange={this.onChangeHandler}/>
</div>
)
}
render() {
let styles = {
display:'inline-block'
}
return (
<div>
<p>Add three buttons and enter the number in each input, and remove amt.</p>
<button id="FirstButton" onClick={this.addButtons}>FirstButton</button>
<button id="SecondButton" onClick={this.addButtons}>SecondButton</button>
<button id="ThirdButton" onClick={this.addButtons}>ThirdButton</button>
<button id="FirstButton" onClick={this.removeButtons}>Remove firstButton</button>
<ul>
{this.state.filtersArr.map((filter, index)=>{
return <li style={styles} key={index}>{filter.p}</li>
})
}
</ul>
</div>
);
}
}
ReactDOM.render(
<ButtonComponent/>,
document.getElementById('root')
);
Share
Improve this question
edited Sep 30, 2017 at 11:08
Isti115
2,7963 gold badges36 silver badges39 bronze badges
asked Sep 28, 2017 at 20:24
As3ScriptAs3Script
1475 silver badges17 bronze badges
2
- 1 You're missing the onChangeHandler function for starters – Peter Commented Sep 28, 2017 at 20:27
- Thanks, @Peter, but it's not related to my issue. anyways, I have added changeHandler :-) – As3Script Commented Sep 28, 2017 at 20:46
3 Answers
Reset to default 4The problem is that you're using the array index as your key
, so React will reuse the first two li
elements and drop the last one. Change key={index}
to key={filter.id}
, and it works as you would expect.
Update concerning the ment & downvote: I assumed uniqueness on filters in the actual code, given that the field is called id
. The CodePen seems more of a stripped down version to show the problem. But if you do actually wish to let each button create multiple text fields, you'd indeed need to add something extra to distinguish the keys (e.g. a counter). This doesn't affect the problem as stated in the question though.
Looking at the code again, I noticed getInput
would be an ideal candidate to extract into a separate (stateless) ponent, e.g. FilterInput
. This fits better with the react model than keeping child renderings in the ponent state.
The code produces 3 textboxes in divs. These textboxes are updated by entering the numbers (100, 200, 300). When you click the RemoveFirstButton, the state, which stores these ponents, is updated and render is called.
The render function does a diff of the current state and the previous state and removes the last div, which contains the number 300. This is because, for the render function, the first element of the array changed from FirstButton to SecondButton, the second element changed from SecondButton to ThirdButton and the third element does not exist anymore.
To make it work as expected, you need to change the key of the elements from the index of the array to the id of the element, so that the render method can tell the difference between the elements.
Edit: Please avoid using your ids as keys as the other answers suggest if multiple of the same elements can be added as your initial example suggests because keys need to be unique and this way they can (and will) be repeated!
Your problem lies in the fact that you are using the key attribute wrongly. React expects your ponents to have constant keys, so it can decide when and which ones it needs to update.
If you are modifying an array, the keys of the objects are changing, and the element that had the key '1' before the removal is gone afterwards and the ponent that previously had key '2' bees the one with key '1' and so forth.
The React documentation advises against using the index as key as well:
"We don’t remend using indexes for keys if the items can reorder"
To avoid this you should use some sort of unique key generation and store each ponents key in it's own object, for example like this:
In the constructor:
this.nextKey = 0
When adding a new ponent:
tempArr.push({p: p, id: e.target.id, key: this.nextKey++});
In the render function:
return <li style={styles} key={filter.key}>{filter.p}</li>
I modified your example to include these lines, you can find it here: https://codepen.io/Isti115/pen/MEmMZP?editors=1111
Also, some other tips:
When creating an object that has a key with a value assigned from a variable with the same name, you can shorten it so that this:
{p: p, id: e.target.id}
bees this:{p, id: e.target.id}
.If you need something more robust, you could use a separate unique key generator like this:
Create GUID / UUID in JavaScript?
or this:
https://gist.github./gordonbrander/2230317
ps.: The switch statement you are using is pletely useless right now. What have you tried to acplish with it?
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744332472a4568954.html
评论列表(0条)