2015-05-26 8 views
7

Я прохожу через учебник по реагированию на tutsplus, который немного стар, и код не работает, поскольку он был изначально написан. Я на самом деле полностью в порядке с этим, поскольку он заставляет меня учиться более самостоятельно, однако я потратил некоторое время на ошибку, которую я просто не могу понять. Ошибка состоит в том, что вы не можете передать ключ объектов, что предотвращает обновление моей программы из состояния правильного объекта.Передача ключей детям в React.js

Во-первых здесь репо, если вы хотите запустить этот код и увидеть его в действии: https://github.com/camerow/react-voteit

У меня есть компонент ребенка, который выглядит следующим образом:

var FeedItem = React.createClass({ 

    vote: function(newCount) { 
    console.log("Voting on: ", this.props, " which should have a key associated."); 

    this.props.onVote({ 
     key: this.props.key, 
     title: this.props.title, 
     description: this.props.desc, 
     voteCount: newCount 
    }); 
    }, 

    voteUp: function() { 
    var count = parseInt(this.props.voteCount, 10); 
    var newCount = count + 1; 
    this.vote(newCount); 
    }, 

    voteDown: function() { 
    var count = parseInt(this.props.voteCount, 10); 
    var newCount = count - 1; 
    this.vote(newCount); 
    }, 

    render: function() { 
    var positiveNegativeClassName = this.props.voteCount >= 0 ? 
            'badge badge-success' : 
            'badge badge-danger'; 
    return (
     <li key={this.props.key} className="list-group-item"> 
     <span className={positiveNegativeClassName}>{this.props.voteCount}</span> 
     <h4>{this.props.title}</h4> 
     <span>{this.props.desc}</span> 
     <span className="pull-right"> 
      <button id="up" className="btn btn-sm btn-primary" onClick={this.voteUp}>&uarr;</button> 
      <button id="down" className="btn btn-sm btn-primary" onClick={this.voteDown}>&darr;</button> 
     </span> 
     </li> 
    ); 
    } 

}); 

Теперь, когда кто-то ударяет кнопка вотума желаемого поведения для метода FeedItem.vote() для отправки объекта до основного компонента Feed:

var FeedList = React.createClass({ 

    render: function() { 
    var feedItems = this.props.items; 

    return (
     <div className="container"> 
     <ul className="list-group"> 

      {feedItems.map(function(item) { 
      return <FeedItem key={item.key} 
          title={item.title} 
          desc={item.description} 
          voteCount={item.voteCount} 
          onVote={this.props.onVote} /> 
      }.bind(this))} 
     </ul> 
     </div> 
    ); 
    } 

}); 

, который должен пройти этот ключ на Thr должно onVote функция родительского компонента:

var Feed = React.createClass({ 

    getInitialState: function() { 
    var FEED_ITEMS = [ 
     { 
     key: 1, 
     title: 'JavaScript is fun', 
     description: 'Lexical scoping FTW', 
     voteCount: 34 
     }, { 
     key: 2, 
     title: 'Realtime data!', 
     description: 'Firebase is cool', 
     voteCount: 49 
     }, { 
     key: 3, 
     title: 'Coffee makes you awake', 
     description: 'Drink responsibly', 
     voteCount: 15 
     } 
    ]; 
    return { 
     items: FEED_ITEMS, 
     formDisplayed: false 
    } 
    }, 

    onToggleForm: function() { 
    this.setState({ 
     formDisplayed: !this.state.formDisplayed 
    }); 
    }, 

    onNewItem: function (newItem) { 
    var newItems = this.state.items.concat([newItem]); 
    // console.log("Creating these items: ", newItems); 
    this.setState({ 
     items: newItems, 
     formDisplayed: false, 
     key: this.state.items.length 
    }); 
    }, 

    onVote: function (newItem) { 
    // console.log(item); 

    var items = _.uniq(this.state.items); 
    var index = _.findIndex(items, function (feedItems) { 
     // Not getting the correct index. 
     console.log("Does ", feedItems.key, " === ", newItem.key, "?"); 
     return feedItems.key === newItem.key; 
    }); 
    var oldObj = items[index]; 
    var newItems = _.pull(items, oldObj); 
    var newItems = this.state.items.concat([newItem]); 
    // newItems.push(item); 
    this.setState({ 
     items: newItems 
    }); 
    }, 

    render: function() { 
    return (
     <div> 
     <div className="container"> 
      <ShowAddButton displayed={this.state.formDisplayed} onToggleForm={this.onToggleForm}/> 
     </div> 
     <FeedForm displayed={this.state.formDisplayed} onNewItem={this.onNewItem}/> 
     <br /> 
     <br /> 
     <FeedList items={this.state.items} onVote={this.onVote}/> 
     </div> 
    ); 
    } 

}); 

Моя логика опирается на возможность согласовать ключи в onVote функции, однако ключ проп не должным образом передается. Итак, мой вопрос: как я могу пройти через этот «один путь потока» к моему родительскому компоненту?

Примечание: Не стесняйтесь указывать на другие проблемы или лучшее дизайнерское решение или абсолютные глупости. Или даже я задаю неправильный вопрос.

С нетерпением ждем прекрасного изучения этой прохладной рамки.

+2

'ключ' имеет специальное значение в Реагировании. Он не доступен для компонента через 'this.props.key' afaik. Для этого вы должны использовать другое имя. Или, если вы действительно хотите использовать значение как ключ, добавьте дополнительную опору с тем же самым, что вы можете затем получить доступ к компоненту. См. Https://facebook.github.io/react/docs/multiple-components.html#dynamic-children –

+0

Ах, хорошо, это очень помогло. Я уже прочитал эту документацию, но был немного озадачен ею. Поэтому, чтобы уточнить, для меня нормально определять prop 'key', но он должен выглядеть как' '? Или я должен избегать «ключа» вообще? – camerow

+0

По-прежнему получать это предупреждение 'Предупреждение: каждый ребенок в массиве или итераторе должен иметь уникальную« ключевую »опору. Проверьте метод рендеринга FeedList. См. Https://fb.me/react-warning-keys для получения дополнительной информации. ', Хотя изменение всех экземпляров' key' на 'id' позволило мне передать эту подсказку. – camerow

ответ

28

The key prop has a special meaning in React. Он не передается компоненту в качестве опоры, а используется Реагтом для содействия согласованию коллекций. Если вы знаете d3, он работает аналогично функции клавиш для selection.data(). Он позволяет React связывать элементы предыдущего дерева с элементами следующего дерева.

Это хорошо, что у вас есть key (и вам нужно, если вы передаете массив элементов), но если вы хотите передать это значение по компоненте, вы должны еще пропеллер:

<FeedItem key={item.key} id={item.key} ... /> 

(и доступ к this.props.id внутри компонента).

+1

Спасибо. Это решило мою проблему с ключами, теперь мне просто нужно исправить логику в моей функции 'onVote'. – camerow

+0

Большое спасибо @Felix. Кстати, вы тоже можете помочь с этим вопросом? Я хочу передать узел как свойство в режиме React: http://stackoverflow.com/questions/34879973/pass-this-refs-as-property-in-jsx-in-react-js – haotang

Смежные вопросы