如何在不使用React重新呈现整个列表的情况下添加新元素

时间:2016-08-22 14:48:45

标签: javascript dom reactjs

我正在开发简单的流应用。我有帖子列表,此列表可以接收更新,这些更新将显示在其上。

问题在于每个新帖子都会收到React重新呈现整个元素列表。我为它做了一个简单的例子。

有没有办法避免这种行为? 我在React docs上看过 dynamic-children 主题,但在例子中,如您所见,我仍然更新了所有孩子。

class Post extends React.Component {
  render() {
    console.log('rerendered post', this.props.reactKey);
    return (
      <li>{this.props.post.text}</li>
    );
  }
}

class App extends React.Component {

  constructor(props) {
    super(props);
    this.state = {posts: [
      {id: '00001', text: 'First one'},
      {id: '00002',text: 'Second one'},
      {id: '00003',text: 'Third one'}
    ]};
  }

  addPost() {
    const posts = this.state.posts;
    posts.unshift({id: '00004', text: 'New post'});
    this.setState({posts: posts});
  }

  render() {
    return (
      <div>
        <button onClick={this.addPost.bind(this)}>Add Post</button>
        <ul>
          {this.state.posts.map((post, index) => {
            return (<Post post={post} key={post.id} reactKey={index} />);
          })}
        </ul>
      </div>
    );
  }
}


ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<body>
  <div id="root"></div>
</body>

解决方案

问题是我使用.map函数的索引是每个列表组件的键而不是唯一键。并且因为添加新元素后列出所有索引更改为+1,所以第一个帖子成为第二个,所有帖子都重新呈现。 因此,首先,检查您是否在所有列表元素中使用唯一键: - )

1 个答案:

答案 0 :(得分:2)

只需要完成一次的工作应该在保证只运行一次的生命周期方法中完成,例如componentDidMount。正如文档所示:

  

如果要与其他JavaScript框架集成,使用setTimeout或setInterval设置计时器,或发送AJAX请求,请在此方法中执行这些操作。

我在您的代码段中添加了componentDidMount的日志记录,以便多次显示渲染,但每个实例只调用componentDidMount一次。

&#13;
&#13;
class Post extends React.Component {
  componentDidMount() {
    console.log('mounted post', this.props.id);
  }

  render() {
    console.log('rerendered post', this.props.id);
    return (
      <li>{this.props.post.text}</li>
    );
  }
}

class App extends React.Component {

  constructor(props) {
    super(props);
    this.nextId = 4;
    this.state = {
      posts: [
        {id: 1, text: 'First one'},
        {id: 2,text: 'Second one'},
        {id: 3,text: 'Third one'},
      ],
    };
  }

  addPost() {
    const posts = this.state.posts;
    posts.unshift({id: this.nextId, text: 'Post ' + this.nextId});
    this.nextId++;
    this.setState({posts: posts});
  }

  render() {
    return (
      <div>
        <button onClick={this.addPost.bind(this)}>Add Post</button>
        <ul>
          {this.state.posts.map((post, index) => {
            return (<Post post={post} key={post.id} id={post.id} />);
          })}
        </ul>
      </div>
    );
  }
}


ReactDOM.render(<App />, document.getElementById('root'));
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<body>
  <div id="root"></div>
</body>
&#13;
&#13;
&#13;