2015-05-26 9 views
7

Używam samouczka reagowania na tutsplus, który jest nieco stary, a kod nie działa tak, jak został pierwotnie napisany. Naprawdę jestem z tym w porządku, ponieważ zmusza mnie to do samodzielnego uczenia się, ale spędziłem trochę czasu na błędzie, którego nie mogę pojąć. Błąd polega na tym, że nie można przekazać klucza obiektu, co uniemożliwia programowi aktualizację stanu poprawnego obiektu.Przekazywanie kluczy do dzieci w React.js

Po pierwsze tu jest repo jeśli chcesz uruchomić ten kod i zobaczyć go w akcji: https://github.com/camerow/react-voteit

Mam składnik podrzędny, który wygląda tak:

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> 
    ); 
    } 

}); 

Teraz, gdy ktoś uderza przycisk głosowanie pożądane zachowanie jest dla metody FeedItem.vote(), aby wysłać obiekt do głównego składnika pasz:

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> 
    ); 
    } 

}); 

Który powinien przekazać ten klucz na Thr powinien onVote funkcją komponentu nadrzędnego:

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> 
    ); 
    } 

}); 

Moja logika opiera się na mogąc pogodzić klawiszy w funkcji onVote jednak kluczem prop nie jest prawidłowo przekazane. Moje pytanie brzmi: jak mogę przekazać klucz do tego "przepływu w jedną stronę" do mojego komponentu nadrzędnego?

Uwaga: Zapraszam do wskazania innych problemów lub lepszej decyzji dotyczącej projektu lub absolutnych głupstw. Albo nawet, że zadaję niewłaściwe pytanie.

Czekamy na miłą eksplorację tego fajnego szkieletu.

+2

'klucz' ma specjalne znaczenie w React. Nie jest dostępny dla komponentu przez 'this.props.key' afaik. Powinieneś użyć do tego innej nazwy. Lub, jeśli rzeczywiście chcesz użyć wartości jako klucza, dodaj dodatkowy element pomocniczy z tym samym, który możesz następnie uzyskać wewnątrz komponentu. Zobacz https://facebook.github.io/react/docs/multiple-components.html#dynamic-children –

+0

Ahh, ok, to pomogło niesamowicie. Przeczytałem już tę dokumentację, ale byłem nieco zakłopotany. Aby wyjaśnić, że jest w porządku zdefiniować klucz 'prop', ale powinien wyglądać tak:' '? A może powinienem unikać "klucza" w ogóle? – camerow

+0

Nadal otrzymuję to ostrzeżenie. Ostrzeżenie: Każde dziecko w tablicy lub iteratorze powinno mieć unikalny "klucz". Sprawdź metodę renderowania FeedList. Zobacz https://fb.me/react-warning-keys, aby uzyskać więcej informacji. ", Chociaż zmiana wszystkich instancji' key' na 'id' pozwoliła mi przekazać ten dokument razem. – camerow

Odpowiedz

28

The key prop has a special meaning in React. Nie jest przekazywany do komponentu jako rekwizyt, ale jest używany przez React, aby pomóc w pogodzeniu kolekcji. Jeśli znasz numer d3, działa on podobnie jak funkcja klucza dla selection.data(). Pozwala to React powiązać elementy poprzedniego drzewa z elementami następnego drzewa.

To dobrze, że masz key (i będzie potrzebny, jeśli przekazać tablicę elementów), ale jeśli chcesz przekazać tę wartość wraz ze składnikiem, należy kolejny rekwizyt:

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

(i dostęp do this.props.id wewnątrz komponentu).

+1

Dziękuję. Rozwiązało to mój problem związany z kluczowaniem, teraz wystarczy naprawić logikę w mojej funkcji 'onVote'. – camerow

+0

Wielkie dzięki @Felix. BTW, czy możesz pomóc również w tym pytaniu? Chcę przekazać węzeł jako właściwość w sposób React: http://stackoverflow.com/questions/34879973/pass-this-refs-as-property-in-jsx-in-react-js – haotang