Facebook React: Invariant Violation и элементы, которые не были автоматически установлены

Я изучаю Facebook React, делая небольшой пример. Я решил проверить, были ли мои знания о привязке this в порядке, поэтому я создал три React.class, где изменяемые состояния находятся в родительском, а посередине только передают обратные вызовы детям, чтобы манипулировать им.

Основная структура:

- MainFrame (states here)
  - FriendBox (only pass the callbacks for change states to Friend)
    -Friend

Заметьте, что я мог бы использовать transferThisProp, но на самом деле я предпочел сделать это "вручную".

Вывод FriendBox содержит следующее:

var allFriends = this.props.friends.map((function (f) {
  return(
    <Friend key = {f.id}
            name = {f.name}
            select = {this.props.select}
    />
  )
}).bind(this))  

Друг-рендер содержит следующее:

return(
  <div className="friend">
    {this.props.name}
    <a href="" onClick={this.props.select(this.props.key)}>
      select
    </a>
  </div>
)

При запуске моего кода я получаю следующее сообщение:

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. 

Интересная часть заключается в том, что при использовании активного расширения для chrome я могу проверить, что виртуальный DOM хорошо, и привязки в порядке. Все выглядит отлично, за исключением того, что компонент Child для первого элемента Friend говорит _lifeCycleState: "UNMOUNTED"

Это заставило меня задуматься, чем я ошибаюсь, когда нижний ребенок не отображается и не монтируется. Весь код выходит из строя, но я точно не знаю почему. Может ли кто-нибудь сказать мне, почему элемент не устанавливается автоматически и как его исправить?

Полный код: http://jsfiddle.net/RvjeQ/

Ответ 1

Когда вы пишете

onClick={this.props.select(this.props.key)}

вы вызываете обработчик this.props.select немедленно и устанавливаете его результат как обработчик onClick. Я предполагаю, что вы хотите вместо этого сделать частичное приложение, которое вы можете использовать с помощью функции стрелки:

onClick={(e) => this.props.select.bind(this.props.key, e)}

Если вы не заботитесь о событии arg, вы можете пропустить его.

Вы также можете использовать .bind() так:

onClick={this.props.select.bind(null, this.props.key)}

Ответ 2

Для чего это стоит, вам не нужно делать

this.props.friends.map((function(){ ... }).bind(this));

Второй аргумент Array.prototype.map позволяет установить контекст для функции обратного вызова. Используйте это вместо

this.props.friends.map(function(f){ ... }, this);

Вы также можете использовать Функция стрелки, которая имеет лексическую область

this.props.friends.map(f =>
  <Friend key = {f.id}
          name = {f.name}
          select = {this.props.select}
  />
)

Кроме того, когда вы работаете со сложными реквизитами, вы можете делать такие вещи, как

var props = {
  key:    f.id,
  name:   f.name,
  select: this.props.select
};

<Friend {...props} />