Warning: setState (...): cannot update during existing state transition

I am developing a simple to-do list application (new to React.js). I am adding items to the list, but deleting the items raises the question. Inside my parent response component, I have the following code:

import ToDoEntries from './to_do_entries.jsx';

class ToDoList extends React.Component {
  constructor(props) {
    super(props);
    this.state = { list: [] }
    this.add = this.addItem.bind(this);
    this.removeItem = this.removeItem.bind(this);
  }

  addItem(e) { //removed to avoid tl:dr }

  render() {
    return(
      <form onSubmit={this.add}>
        <input placeholder='Enter item' type='text' ref={(el) => {this._input = el;} }/>
        <button>Add</button>
      </form>

      <ToDoEntries entries={this.state.list}
        removeCallback={this.removeItem}
      />
    );
  }

}

My to_do_entries.jsxcomponent:

class ToDoEntries extends React.Component {
  constructor(props) {
    super(props);
  }

  renderItems() {
    const { entries, removeCallback } = this.props;

    function createTasks(item) {
      return <li key={item.key}>{item.text}</li>
    }

    var listItems = entries.map(function(item) {
      return(<li onClick={removeCallback} key={item.key}>{item.text}</li>)
    })

    return listItems;
  }

  render() {
    var todoEntries = this.renderItems();

    return(
      <ul>
        {todoEntries}
      </ul>
    );
  }
}

export default ToDoEntries;

Running this code:

Warning: setState (...): cannot update during existing state Transition

Question:

why rendering to_do_entries.jsximmediately calls back when adding ie element:

var listItems = entries.map(function(item) {
  return(<li onClick={removeCallback(id)} key={item.key}>{item.text}</li>)
})

However, adding .bind(null, id)to remove Callback, i.e. <li onClick={removeCallback.bind(null, id)} />not?

+4
source share
3 answers

, . todo, , , . todo , .

onClick , todo <li> , , . .bind , , , .

, , . todo , . , , . https://codepen.io/w7sang/pen/VWNLJp

// App
class App extends React.Component{
  constructor(props) {
    super(props);
    this.state = { list: [] }
    this.add = this.addItem.bind(this);
    this.removeItem = this.removeItem.bind(this);
  }
  addItem(e) { 
    e.preventDefault();
    this.setState({
      list: [ 
        ...this.state.list, 
        {
          key: Math.random(1,10000),
          text: this._input.value
        }
      ]
    })
  }
  removeItem(payload){
    this.setState({
      list: [ 
        ...this.state.list.slice(0, payload.index),
        ...this.state.list.slice(payload.index + 1)
      ]
    })
  }
  render() {
    return(
      <div>
        <form onSubmit={this.add}>
          <input placeholder='Enter item' type='text' ref={(el) => {this._input = el;} }/>
          <button>Add</button>
        </form>
        <ToDoEntries entries={this.state.list} removeItem={this.removeItem} />
      </div>
    );
  }
}

// TodoEntries [STATELESS]
const ToDoEntries = ({ entries, removeItem } ) => {
  return(
    <ul>
      { entries.map((item, index) => {
        return(<Todo key={item.key} index={index} item={item} removeItem={removeItem} />)
      }) }
    </ul>
  );
}

// Todo
class Todo extends React.Component {
  constructor(props){
    super(props);
    this.state = {};
    this.remove = this.remove.bind(this);
  }
  remove() {
    const { index, removeItem } = this.props;
    removeItem({
      index
    });
  }
  render() {
    return <li onClick={this.remove}>{this.props.item.text}</li>
  }
}

ReactDOM.render(<App />,document.getElementById('app'));
<div id="app"></div>
+2

:

onClick={removeCallback(id)}

onClick, . () Name, , onClick, , setState removeCallback, :

render ->  removeCallback()  ->  setState ->
  ^                                         |
  |                                         |
  |                                         |
   -----------------------------------------

.

abc and abc():

function abc(){
   return 'Hello';
}

console.log('without () = ', abc);     //will return the function
 
console.log('with () = ', abc());      //will return the function result (value)

onClick={removeCallback.bind(null, id)}?

bind , removeCallback , - .

MDN Doc:

bind() (BF). BF ( ECMAScript 2015), . BF .

React DOC: JSX.

bind: JavaScript

+3

to_do_entries.jsx ?

, todo <li/> removeCallback onClick.

,

<li onClick={removeCallback(id)} </li>

:

var result = removeCallback(id);
<li onClick={result} </li>

, bind . , .

. mdn, :

bind... , ...

In your case, when you use bind and provide this onClick, you create a new function that will be called when the click event actually fires, and not when this element is rendered.

Another way to look at removeCallback.bind(null, id)it is as follows:

var newFunc = () => {
  return removeCallback(id);
}
<li onClick={newFunc} </li>
+2
source

Source: https://habr.com/ru/post/1681537/


All Articles