I'm developing a simple 'to do list' react app (new to React.js). I have adding items to a list working but deleting items raises a question. Within my parent react 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.jsx
component:
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 bring:
Warning: setState(…): Cannot update during an existing state transition
Question:
why does to_do_entries.jsx
's render immediately execute the callback when an item gets added i.e:
var listItems = entries.map(function(item) {
return(<li onClick={removeCallback(id)} key={item.key}>{item.text}</li>)
})
However, adding .bind(null, id)
to removeCallback ie. <li onClick={removeCallback.bind(null, id)} />
does not?
Problem is in this part:
onClick={removeCallback(id)}
We need to pass a function to onClick, not the value. When we use ()
with functionName, that means you are calling that method and assigning the result of that to onClick
, that will create a infinite loop if you do setState
in removeCallback, because of this cycle:
render -> removeCallback() -> setState ->
^ |
| |
| |
-----------------------------------------
That's why you are getting the error.
Check the snippet for difference between 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)
Why it is working with
onClick={removeCallback.bind(null, id)}
?
Because bind will create a new function, and assign that function to click event, here removeCallback
will get called when you click on any item not automatically.
As per MDN Doc:
The bind() function creates a new bound function (BF). A BF is an exotic function object (a term from ECMAScript 2015) that wraps the original function object. Calling a BF generally results in the execution of its wrapped function.
Check the React DOC: Handling events in JSX.
Check this answer for more details about bind: Use of the JavaScript 'bind' method
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With