web-dev-qa-db-ja.com

React.js-コンポーネントの並べ替えの実装

私はReactの概念、特にre:状態と動的UIを、小さなスポーツ名簿のようなUIをコーディングすることで学習しようとしています。以下のコードを含め、アプリ全体とビジュアルはat http://codepen.io/emkk/pen/dGYXJO 。このアプリは基本的に、以前に定義したプレーヤーオブジェクトの配列からプレーヤーカードを作成します。

ボタンクリックでプレイヤーカードのソートを実装したいと思います。上記のボタンをレンダリングする<Sort/>コンポーネントを作成しました。イベントリスナーをアタッチしますが、それを<Roster/>コンポーネントに反映させる方法がわかりません。私はthis.stateでさまざまなアプローチを試しましたが、これを機能させることができないようです。したがって、並べ替えの実装に関するヘルプや一般的なアドバイスは非常に高く評価されます!

class ProfileCard extends React.Component {
  render() {
    return (
      <section className="profile-card">
        <figure>
          <img src={this.props.player.picURL} alt={this.props.player.Name}></img>
          <article>
            <ul>
              <li>{this.props.player.Name}</li>
              <li>{this.props.player.position}, #{this.props.player.number}</li>
              <li>{this.props.player.Club}</li>
              <li>{this.props.player.Height} ({this.props.player.Meters} m)</li>
              <li>{this.props.player.Age} years old</li>
            </ul>
          </article>
        </figure>
      </section>
    );
  }
}

class Roster extends React.Component {
  render() {

    // Store sorted version of data
    // Where I'd implement selected sorting
    var sorted = this.props.players.sort();

    /*
    * Create player cards from JSON collection
    */
    var cards = [];
    sorted.forEach(function(player) {
      if (player.year > 2000) {
        cards.Push(<ProfileCard player={player} />);
      }
    });

    return (<div>{cards}</div>);
  }
}

class Sort extends React.Component {
  render() {
    return (
      <div className="sort-section">
        <h1>Sort by</h1>
        <div className="pill" id='age'>Age</div>
        <div className="pill" id='Meters'>Height</div>
        <div className="pill" id='Name'>Name</div>
      </div>
    )
  }
}

class SortablePlayerTable extends React.Component {

  render() {
    /*
    * Prefix some interestings stats
    * before roster
    */
    var ages = [], heights = [];

    this.props.players.forEach(function(player) {
      if (player.year > 2000) {
        ages.Push(player.Age);
        heights.Push(player.Meters);
      }
    });
    var avgAge = (ages.reduce( (a, b) => a + b) / 12).toPrecision(3);
    var avgHeights = (heights.reduce( (a, b) => a + b) / 12).toPrecision(3);

    // Return page with stats data and Roster
    return (
      <div>
        <h1>2012 Olympic Men's Basketball Team</h1>
        <h2>Average Age: {avgAge} years old</h2>
        <h2>Average Height: 6 ft 7 in ({avgHeights} m)</h2>
        <Sort/>
        <Roster 
                players={this.props.players} 
        />
      </div>
    );
  }
};

React.render(
  <SortablePlayerTable players={PLAYERS} />,
  document.getElementById('container')
);

ソリューション:

これに至るまでに私をつまずかせたもう1つのことは、this.setStateへのアクセスを失い、this.setState is a not a functionエラーが発生し続けることでした。 ES6の矢印関数を使用してthisをハンドラー関数に字句的にバインドすることで、私を救いました。

class ProfileCard extends React.Component {
  render() {
    return (
      <section className="profile-card">
        <figure>
          <img src={this.props.player.picURL} alt={this.props.player.Name}></img>
          <article>
            <ul>
              <li>{this.props.player.Name}</li>
              <li>{this.props.player.position}, #{this.props.player.number}</li>
              <li>{this.props.player.Club}</li>
              <li>{this.props.player.Height} ({this.props.player.Meters} m)</li>
              <li>{this.props.player.Age} years old</li>
            </ul>
          </article>
        </figure>
      </section>
    );
  }
}

class Roster extends React.Component {
  render() {
    // Create player cards from sorted, dynamic JSON collection
    var cards = [];
    this.props.players.forEach(function(player) {
      if (player.year > 2000) {
        cards.Push(<ProfileCard player={player} />);
      }
    });

    return (<div>{cards}</div>);
  }
}

class Sort extends React.Component {
  sortRoster(field){
    var players = this.props.players;
    this.props.sortRosterStateBy(field, players);
  }
  render() {
    return (
      <div className="sort-section">
        <h1>Sort by</h1>
        <div className="pill" onClick={this.sortRoster.bind(this,'Age')} >Age</div>
        <div className="pill" onClick={this.sortRoster.bind(this,'Meters')} >Height</div>
        <div className="pill" onClick={this.sortRoster.bind(this,'Name')} >Name</div>
        <div className="pill" onClick={this.sortRoster.bind(this,'position')} >Position</div>
        <div className="pill" onClick={this.sortRoster.bind(this,'number')} >Number</div>
        <div className="pill" onClick={this.sortRoster.bind(this,'Club')} >Club</div>
      </div>
    )
  }
}

class SortablePlayerTable extends React.Component {
  state = {
   'players': this.props.players // default state
  }

  sortRosterStateBy = (field, players) => {
    // Sorting ...
    var sortedPlayers = players.sort( (a, b) => {
      if (a[field] > b[field]) {
        return 1;
      }
      if (a[field] < b[field]) {
        return -1;
      }
      return 0;
    });

    // Then call setState
    this.setState({'players': sortedPlayers});
  }

  render() {
    // Prefix some interestings stats before roster
    var ages = [], heights = [];
    this.props.players.forEach(function(player) {
      if (player.year > 2000) {
        ages.Push(player.Age);
        heights.Push(player.Meters);
      }
    });
    var avgAge = (ages.reduce( (a, b) => a + b) / 12).toPrecision(3);
    var avgHeight = (heights.reduce( (a, b) => a + b) / 12).toPrecision(3);

    // Return page with stats data and Roster
    return (
      <div>
        <h1>2012 Olympic Men's Basketball Team</h1>
        <h2>Average Age: {avgAge} years old</h2>
        <h2>Average Height: 6 ft 7 in ({avgHeight} m)</h2>
        <Sort players={this.props.players} sortRosterStateBy={this.sortRosterStateBy}/>
        <Roster players={this.state.players}/>
      </div>
    );
  }
};

ReactDOM.render(
  <SortablePlayerTable players={PLAYERS} />,
  document.getElementById('container')
);
7
Edmund Korley

_<div/>_の各_<Sort/>_に、親関数を呼び出すthis.props.sortBy()をクリックして関数をアタッチします

_class Sort extends React.Component {
  sort(field){
    this.props.sortBy(field);
  }
  render() {
    return (
      <div className="sort-section">
        <h1>Sort by</h1>
        <div className="pill" id='age' onClick=this.sort.bind(this,'age')>Age</div>
        <div className="pill" id='Meters' onClick=this.sort.bind(this,'height')>Height</div>
        <div className="pill" id='Name' onClick=this.sort.bind(this,'name')>Name</div>
      </div>
    )
  }
}
_

この親関数sortByを_<SortablePlayerTable/>_コンポーネントからpropsとして渡します。

_class SortablePlayerTable extends React.Component {
  state = {
   players: [] // default state
  }
  sortBy(field){
    // Your sorting algorithm here
    // it should Push the sorted value by field in array called sortedPlayers 
    // Then call setState
    this.setState({
      players: sortedPlayers
    });
  }
  render() {
    // calculate stats
    return (
      <div>
        {/* some JSX */}
        <Sort sortBy={sortBy}/>
        <Roster 
                players={this.state.players} 
        />
      </div>
    );
  }
};
_

これで、並べ替えられた配列が_<Roster/>_コンポーネントで_this.props.players_として使用できるようになります。 _<Roster/>_コンポーネント内で並べ替えを適用せずに、配列を直接レンダリングします。

14