本文介绍了如何添加新元素而不用React重新整理列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发简单的流应用程序。我有列表的帖子,这个列表可以接收更新,这将显示在它的顶部。



问题是在每个新的帖子收到React重新递归整个元素列表。我已经做了简单的例子。



有没有办法避免这种行为?
我看到了React文档中的 动态孩子 主题,但是,如您所见,我已经将所有的孩子都更新了。



  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)}>添加发布< / 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,所以第一个帖子成为第二个,我的所有帖子都被重新呈现。
所以起初,请检查所有列表元素中使用唯一的键: - )

解决方案

只能在一个生命周期方法中完成一次,该方法只能运行一次,如。如文档建议:

我在你的代码段中添加了日志记录到 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)}>添加发布< / 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'));  
 < 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>  


I'm working on simple stream app. I have list of posts and this list can receive updates, which will display on top of it.

The problem is on each new post receive React rerenders the whole list of elements. I've made simple example for it.

Is there any way to avoid this behaviour?I've seen the dynamic-children topic on React docs, but in example, as you see, I have all children updated anyway.

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>

The solution

The problem was that I used index of .map function is a key for each list component instead of unique key. And because after adding new element to list all indexes changes to +1, so the first post becomes the second, all my posts have re-rendered.So at first, check you use unique keys across all list elements :-)

解决方案

Work that needs to be done only once should be done in a lifecycle method that is guaranteed to run only once, like componentDidMount. As the docs suggest:

I added logging to componentDidMount in your snippet to show rendering happens many times, but componentDidMount is called only once per instance.

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'));
<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>

这篇关于如何添加新元素而不用React重新整理列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-18 19:24