A simple example:

class Element extends Component { constructor(props) { super(props); this.state = { name: props.name } } render() { return <p>{this.state.name}</p> } } class Elements extends Component { constructor(props) { super(props); this.state = { names: props.names } } render() { return <div>{ this.state.names.map(function(name, i) { return <Element key={ i } name={ name } /> }) }</div> } componentWillMount() { setTimeout( () => { this.state.names.splice(1, 1); let names = this.state.names; this.setState({names: names}); }, 3000 ); } } ReactDOM.render( <Elements names={ [0, 1, 2] } />, document.body ); 

In general, create the Element . It takes the name in the properties. We write name in the state name . And display the state name .

Elements takes in the names property - the name array for the Element . names writes to its state names . The names state passes in the output and for each creates an Element , passing the next name to the properties to it.

Further setTimeout is just for example, no matter how, but the state of the names of Elements changes. Any name is removed from it. As a result, all Elements are redrawn and each has its own name property. But the state name does not change.

Began to check - yes, the constructor does not work when the Element is redrawn. ComponentWillMount too. ComponentWillUnmount works for one element, but not for the one that was deleted, but for the latter for some reason.

In short, in the end everything looks like this: First on the monitor 0 1 2 and then 0 1 . A must be 0 2 .

Neither can I understand why this is happening ...

    2 answers 2

    It's all about the key attribute for Element :

     render() { return <div>{ this.state.names.map(function(name, i) { return <Element key={ i } name={ name } /> }) }</div> } 

    key must be unique for related iterated items. Here key is the array index.

    The element from the array is deleted, and its index remains and is added to the key of another element. Because of this, React defines an element such as the one that has already been deleted.

      Yes, you correctly identified the "physical" source of the problem, but I'm not sure that you understood what a bad practice led to this.

      This one:

       this.state.names.splice(1, 1); 

      You cannot directly change state.

       this.state.smth = smthelse; // не надо так this.setState({ //надо так smth: smthelse }) 

      It is worth behaving like this with the state, precisely because the state changes do not conflict with the internal mechanisms of the reactor.
      By the way, the documentation also says this:

      Never mutate this.state directly, as calling setState () afterwards may replace the mutation you made. Treat this.state as if it were immutable.

      In your example, try something like this:

       let newNames = [...this.state.names.slice(0,1), ...this.state.names.slice(2)]; this.setState({ names: newNames }); 

      More examples of how to deal with arrays as with out of the box here .

      Also, when working in react-redux, libraries are often used that provide immutable out-of-the-box structures , such as Immutable.js

      About the physical meaning of the key. The virtual dom rearrangement is generally an operation of complexity O (n ^ 3). That for all lists - a very long time. The key indication is a way of saying that a complete restructuring in fact is not needed (most practical cases), and reduce the complexity of this operation to O (n). Well, that is, the key is needed, without it, there are chances to run into a stupid out of the blue.