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

Nik*_*kiy 7 javascript dom reactjs

我正在研究简单的流应用程序.我有帖子列表,此列表可以接收更新,这些更新将显示在其上.

问题出现在每个新帖子上,React会重新呈现整个元素列表.我为它做了一个简单的例子.

有什么方法可以避免这种行为吗?我已经在React docs上看到了动态子主题,但是在例子中,正如你所看到的,无论如何我都会更新所有孩子.

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'));
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

解决方案

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

Ros*_*len 3

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

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

我在代码片段中添加了日志记录componentDidMount以显示渲染发生多次,但componentDidMount每个实例仅调用一次。

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'));
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

  • 谢谢罗斯。实际的问题是(因为我是 React 新手)我没有在所有列表元素中使用唯一的键。我只使用了映射函数索引值,当然在添加新元素以列出所有元素后,我的所有元素都已重新渲染,因为每个元素的键值都已更改。 (2认同)