Skip to content

Instantly share code, notes, and snippets.

@EFox2413
Last active July 13, 2016 21:50
Show Gist options
  • Save EFox2413/d5130f82e75a614620350346f98bcef3 to your computer and use it in GitHub Desktop.
Save EFox2413/d5130f82e75a614620350346f98bcef3 to your computer and use it in GitHub Desktop.
React leaderboard component of Rails webapp designed for FCC React leaderboard project, uses bootstrap for some CSS. Live version at www.efox.us/leaderboard/show
var Leaderboard = React.createClass({
propTypes: {
recentArr: React.PropTypes.array,
alltimeArr: React.PropTypes.array,
reverseBool: React.PropTypes.bool
},
getDefaultProps: function() {
return {
recentArr: [],
alltimeArr: [],
reverseBool: false
};
},
// sets initial state values
getInitialState: function() {
return {
data: [], sortBy: '',
id: 'recent'
};
},
// setup for initial view
componentDidMount: function() {
var urlStr = 'https://fcctop100.herokuapp.com/api/fccusers/top/';
// preloads images to cut down on DOM render time
function preload(array) {
array.forEach(function(entry) {
(new Image()).src = entry.img;
});
}
this.serverRequest = $.get(urlStr + 'recent', function (result) {
this.recentArr = result;
this.setState({sortBy: '', data: result});
preload(result);
}.bind(this));
this.serverRequest = $.get(urlStr + 'alltime', function (result) {
this.alltimeArr = result;
this.setState({sortBy: ''});
preload(result);
}.bind(this));
},
componentWillUnmount: function() {
this.serverRequest.abort();
},
// sets the sort state, sorting is handled in the render method of UserTable
handleClick: function(sortBy) {
this.setState({
sortBy: sortBy
});
},
// this changes which page's data we display
changeReq: function() {
if (this.state.id === 'recent') {
this.setState({data: this.alltimeArr, id: 'alltime'});
} else if( this.state.id === 'alltime') {
this.setState({data: this.recentArr, id: 'recent'});
}
},
render: function() {
return (
<div className="leaderboard">
<Title
changeReq={this.changeReq} />
<HeadRow
onChange={this.handleClick}
sortBy={this.state.sortBy} />
<UserTable
data={this.state.data}
sortBy={this.state.sortBy} />
</div>
);
}
});
var Title = React.createClass({
handleClick: function() {
this.props.changeReq();
},
render: function() {
return (
<h2 className="title" onClick={this.handleClick}>
Leaderboard
<small>Last 30</small>
<small>All time</small>
</h2>
);
}
});
var HeadRow = React.createClass({
render: function() {
return (
<div className="row" >
<div className="col-xs-1"> Avatar </div>
<NameButton
sortBy={this.props.sortBy}
reverseBool={this.props.reverseBool}
onChange={this.props.onChange} />
<ScoreButton
sortBy={this.props.sortBy}
onChange={this.props.onChange} />
<RecentButton
sortBy={this.props.sortBy}
onChange={this.props.onChange} />
<ActivityButton
sortBy={this.props.sortBy}
onChange={this.props.onChange} />
</div>
);
}
});
var UserRow = React.createClass({
render: function() {
var imageStyle = { 'marginTop': '10px'};
return (
<div className="row" key={ this.props.index }>
<img className="img-fluid img-circle col-xs-1" style={imageStyle} src={ this.props.img }/>
<div className="col-xs-2">{this.props.username}</div>
<div className="col-xs-1">{this.props.alltime}</div>
<div className="col-xs-1">{this.props.recent}</div>
<div className="col-xs-1">{this.props.lastUpdate}</div>
</div>
);
}
});
var UserTable = React.createClass({
render: function() {
var rows = this.props.data.slice();
var sortStr = this.props.sortBy;
// sort function, sort by property sortBy
rows = rows.sort(function(a, b) {
if (sortStr != '') {
if (typeof a[sortStr] === 'number') {
if (a[sortStr] > b[sortStr] ) return 1;
else if (a[sortStr] === b[sortStr]) return 0;
else return -1;
} else {
if (a[sortStr].toLowerCase() > b[sortStr].toLowerCase() ) return 1;
else if (a[sortStr].toLowerCase() === b[sortStr].toLowerCase()) return 0;
else return -1;
}
}
});
if (this.props.reverseBool) {
rows = rows.reverse();
}
// map each entry to html
rows = rows.map(function(entry, index) {
return <UserRow key={index} img={entry.img} username={entry.username} alltime={entry.alltime} recent={entry.recent} lastUpdate={entry.lastUpdate} />;
});
return (
<div>
{rows}
</div>
);
}
});
var NameButton = React.createClass({
// bubbles up to leaderboard handleClick function
handleClick: function() {
// if already sorted reverse sorting
var prop = this.props.sortBy;
if (prop === 'username') {
this.props.reverseBool = !this.props.reverseBool;
} else { this.props.reverseBool = false; }
this.props.onChange('username');
},
render: function() {
return ( <div className="col-xs-2" onClick={this.handleClick}> Username </div> );
}
});
var ScoreButton = React.createClass({
handleClick: function() {
var prop = this.props.sortBy;
if (prop === 'alltime') {
this.props.reverseBool = !this.props.reverseBool;
} else { this.props.reverseBool = false; }
this.props.onChange('alltime');
},
render: function() {
return ( <div className="col-xs-1" onClick={this.handleClick}> Score </div> );
}
});
var RecentButton = React.createClass({
handleClick: function() {
var prop = this.props.sortBy;
if (prop === 'recent') {
this.props.reverseBool = !this.props.reverseBool;
} else { this.props.reverseBool = false; }
this.props.onChange('recent');
},
render: function() {
return ( <div className="col-xs-1" onClick={this.handleClick}> Recent </div> );
}
});
var ActivityButton = React.createClass({
handleClick: function() {
var prop = this.props.sortBy;
if (prop === 'lastUpdate') {
this.props.reverseBool = !this.props.reverseBool;
} else { this.props.reverseBool = false; }
this.props.onChange('lastUpdate');
},
render: function() {
return ( <div className="col-xs-1" onClick={this.handleClick}> Activity </div> );
}
});
@EFox2413
Copy link
Author

EFox2413 commented Jul 13, 2016

[21:53] reactjs034, your state should probably be an id instead of a url, like order: 'recent'
[21:54] and then you compute the url as needed

[21:55] reactjs034, line 34 creates a global variable; you should enable strict mode to catch things like that

[21:58] reactjs034, you shouldn't use global variables at all in react
[21:59] reactjs034, you probably want to store that data in the parent's state
[21:59] modifying a global variable won't cause a rerender, so it can get out of sync

[21:56] reactjs034, line 138 you should slice before sorting; both because immutability is a good and because js array.sort is unstable
[21:57] reactjs034, the sort function should return 0 if they're equal

[22:05] GreenJello, oh I do have one immediate question. I noticed on the webpage that when i sort things differently most things are instant but the images have a bit of a lag before they change. Is there a way to cache them so they are as quickly updated as the text elements?

[22:08] you can preload the images and if they have the correct cache headers they'll load from the cache instead of downloading when you update the url

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment