React.js - Implementing sorting of components
Attach a function to each <div/>
in <Sort/>
on clicking which it calls a parent function 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>
)
}
}
Pass this parent function sortBy
as props
from your <SortablePlayerTable/>
component.
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>
);
}
};
Now the sorted array will be available to your <Roster/>
component as this.props.players
. Render the array directly without applying any sort inside <Roster/>
component.
Admin
Updated on March 25, 2020Comments
-
Admin about 4 years
I'm trying to learn React concepts, especially re: state and dynamic UIs, by coding a small sports roster-like UI. I've included the code below and the whole app + visual is at http://codepen.io/emkk/pen/dGYXJO. This app basically creates player cards from an array of player objects I've defined earlier.
I would like to implement sorting of the player cards upon button click. I've created a
<Sort/>
component that renders the said buttons. I'd attach event listeners but don't know how to have that reflected in my<Roster/>
component. I have tried many different approaches withthis.state
but can't seem to be get this to work. So please any help with implementing sorting or general advice would be much apprieciated!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') );
Solution:
Another thing that tripped me up on the way to this was that I was losing access to
this.setState
, kept getting athis.setState is a not a function
error. Using a ES6 arrow function to lexically bindthis
for my handler function rescued me though.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') );