I have this react code where i am using new Date().getTime() as react key props on some Input components.This is probably an antipattern because keys need to be stable. But i want to understand why is this so buggy. And why newDate().getTime() as key behaves worse than Math.random() as key.Please check these 2 examples out to see what i mean:
- example with Math.random() as key
- example with new Date().getTime() as key
The kind of code in question:
class TextInputs extends React.Component {
state = {
textArray: ['hi,','My','Name','is']
};
handleChange = ({value, index}) => {
const {textArray} = this.state;
textArray[index] = value;
this.setState({textArray})
};
render(){
console.log(this.state.textArray)
return this.state.textArray.map((txt, i) => <Input onChange={this.handleChange} index={i} value={txt} key={new Date().getTime()}/>)
};
};
I have this react code where i am using new Date().getTime() as react key props on some Input components.This is probably an antipattern because keys need to be stable. But i want to understand why is this so buggy. And why newDate().getTime() as key behaves worse than Math.random() as key.Please check these 2 examples out to see what i mean:
- example with Math.random() as key
- example with new Date().getTime() as key
The kind of code in question:
class TextInputs extends React.Component {
state = {
textArray: ['hi,','My','Name','is']
};
handleChange = ({value, index}) => {
const {textArray} = this.state;
textArray[index] = value;
this.setState({textArray})
};
render(){
console.log(this.state.textArray)
return this.state.textArray.map((txt, i) => <Input onChange={this.handleChange} index={i} value={txt} key={new Date().getTime()}/>)
};
};
Share
Improve this question
asked Jul 25, 2018 at 17:05
Shady Pillgrim Shady Pillgrim
1751 gold badge2 silver badges10 bronze badges
3 Answers
Reset to default 8This is probably an antipattern because keys need to be stable.
Indeed. :-)
But i want to understand why is this so buggy. And why newDate().getTime() as key behaves worse than Math.random() as key.
Because you can render lots of elements within the same millisecond. A millisecond is a very short time to humans. To computers, not so much. So you end up with keys that aren't unique.
Before you (or anyone reading this) is tempted to reach for performance.now()
instead, remember that as you said, keys need to be stable, and also performance.now()
's accuracy opened the door to some attacks and so implementations have backed off (it's still really precise, but not accurate to the 5 microseconds it was originally supposed to be).
Side note: This code is wrong:
handleChange = ({value, index}) => {
const {textArray} = this.state;
textArray[index] = value;
this.setState({textArray})
};
There are two problems with that code, both described on this page in the documentation:
You're modifying state directly, when assigning to the array entry. You must copy the array and modify the copy.
You're using the non-callback version of
setState
to set state based on existing state. When setting state based on existing state, you must use the callback version ofsetState
.
Ideally, don't use array indexes for this at all; use a unique ID on the object. But if you use an index, the correct code would be:
handleChange = ({value, index}) => {
// Remember the string we're supposed to remove
const entry = this.state.textArray[index];
this.setState(({textArray}) => { // <== Note destructuring
// Find the first occurrence in the array as it is NOW (it may have changed)
const index = textArray.indexOf(entry);
// If the entry is still there...
if (index != -1) {
// ...create a copy of the array without it, return the state update
return {textArray: textArray.filter((e, i) => i !== index)};
// Or:
// textArray = textArray.slice();
// textArray.splice(index, 1);
// return {textArray};
// Or:
// return {textArray: [...textArray.slice(0, index), ...textArray.slice(index + 1)]};
}
});
};
You're changing the key every time that renders, defeating the purpose of keys in react. The key is meant to allow React to keep track of the diffs in components so it know what/when to re-render. In this case, if you don't have a natural key it's best using i
Keys need to be consistent. Read more here: https://reactjs.org/docs/lists-and-keys.html
The reason your app is behaving weirdly is that keys are not unique. The resolution of the new Date().getTime()
is millisecond. When you do that in the loop it's faster than a single millisecond so some of the items get the same key.
Try running for (let i = 0; i < 100; i++) { console.log((new Date).getTime()) }
in the browser's console and see the result.