最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - new Date as react key prop? - Stack Overflow

programmeradmin1浏览0评论

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
Add a comment  | 

3 Answers 3

Reset to default 8

This 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:

  1. You're modifying state directly, when assigning to the array entry. You must copy the array and modify the copy.

  2. 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 of setState.

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.

发布评论

评论列表(0)

  1. 暂无评论