Cómo agregar nuevos elementos sin volver a generar una list completa con React

Estoy trabajando en la aplicación de transmisión simple. Tengo una list de publicaciones y esta list puede recibir actualizaciones, que se mostrarán en la parte superior.

El problema es que cada nueva publicación recibida Reacciona toda la list de elementos. He hecho un ejemplo simple para eso.

¿Hay alguna forma de evitar este comportamiento? He visto el tema de niños dynamics en Reaccionar documentos, pero en el ejemplo, como ve, tengo todos los niños actualizados de todos modos.

class Post extends React.Component { render() { console.log('rerendenetworking 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> 

La solución

El problema fue que utilicé el índice de la function .map es una key para cada componente de list en lugar de una key única. Y porque después de agregar un nuevo elemento a la list todos los índices cambia a +1, por lo que la primera publicación se convierte en la segunda, todas mis publicaciones se han reintegrado. Entonces, al principio, compruebe que utiliza keys únicas en todos los elementos de la list 🙂

El trabajo que debe hacerse solo una vez debe realizarse en un método de ciclo de vida que se garantiza que se ejecutará solo una vez, como componentDidMount . Como sugieren los documentos:

Si desea integrarse con otros frameworks de JavaScript, establecer timeres usando setTimeout o setInterval, o enviar requestes AJAX, realice esas operaciones en este método.

Agregué el logging a componentDidMount en su fragment para mostrar que la representación ocurre muchas veces, pero se llama a componentDidMount solo una vez por instancia.

 class Post extends React.Component { componentDidMount() { console.log('mounted post', this.props.id); } render() { console.log('rerendenetworking 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>