I am learning Facebook React by doing a small example.
I decided check if my knowledge about the this
binding was ok so I created three React.class
where the mutable states are in the parent and the middle only pass the callbacks to the children to manipulate it.
Basic structure:
- MainFrame (states here)
- FriendBox (only pass the callbacks for change states to Friend)
-Friend
Notice than I could use transferThisProp
but actually I preferred made this "manually".
FriendBox render contains this:
var allFriends = this.props.friends.map((function (f) {
return(
<Friend key = {f.id}
name = {f.name}
select = {this.props.select}
/>
)
}).bind(this))
Friend render contains this:
return(
<div className="friend">
{this.props.name}
<a href="" onClick={this.props.select(this.props.key)}>
select
</a>
</div>
)
When running my code I get the following message:
MainFrame.sendToFriendH:
Invariant Violation: receiveComponent(...):
Can only update a mounted component. react.js:7276
Uncaught Error: Invariant Violation:
receiveComponent(...): Can only update a mounted component.
The interesting part is that when using the react extension for chrome I can check that the virtual DOM
is well and the bindings are ok. Everything looks fine except than the Child component for the first Friend
element says _lifeCycleState: "UNMOUNTED"
This made me think than I am doing a mistake where the bottom child is not being rendered and mounted. All the code fails but I don't know exactly why. Can anyone can tell me why the element is not automatically mounted and how can I fix it?
Full Code: http://jsfiddle.net/RvjeQ/
When you write
onClick={this.props.select(this.props.key)}
you're calling the this.props.select
handler immediately and setting its result as the onClick handler. I'm guessing you want to instead do a partial application, which you can do using an arrow function:
onClick={(e) => this.props.select.bind(this.props.key, e)}
If you don't care about the event arg, you can skip it.
You can also use .bind()
like so:
onClick={this.props.select.bind(null, this.props.key)}
For what it's worth, you don't have to do
this.props.friends.map((function(){ ... }).bind(this));
The second argument to Array.prototype.map allows you to set the context for the callback function. Use this instead
this.props.friends.map(function(f){ ... }, this);
You could also use an Arrow Function that has lexical scope
this.props.friends.map(f =>
<Friend key = {f.id}
name = {f.name}
select = {this.props.select}
/>
)
Also, when you're working with complex props, you can do things like
var props = {
key: f.id,
name: f.name,
select: this.props.select
};
<Friend {...props} />
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