Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Facebook React: Invariant Violation and elements than didn't mount automatically

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/

like image 678
user1050817 Avatar asked Feb 04 '14 14:02

user1050817


2 Answers

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)}
like image 158
Sophie Alpert Avatar answered Nov 19 '22 12:11

Sophie Alpert


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} />
like image 23
Mulan Avatar answered Nov 19 '22 12:11

Mulan