Skip to content

Instantly share code, notes, and snippets.

@devNoiseConsulting
Created April 16, 2018 01:22
Show Gist options
  • Select an option

  • Save devNoiseConsulting/ddc930ca5db7d428cf0ddc4edb5708c0 to your computer and use it in GitHub Desktop.

Select an option

Save devNoiseConsulting/ddc930ca5db7d428cf0ddc4edb5708c0 to your computer and use it in GitHub Desktop.
Free React.js Bootcamp, Day 3 Challenge
<!DOCTYPE html>
<html>
<head>
<title>Popular Repos</title>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src='https://unpkg.com/babel-standalone@6/babel.min.js'></script>
</head>
<body>
<div id='app'></div>
<script>
window.API = {
fetchPopularRepos(language) {
// "language" can be "javascript", "ruby", "python", or "all"
const encodedURI = encodeURI(`https://api.github.com/search/repositories?q=stars:>1+language:${language}&sort=stars&order=desc&type=Repositories`)
return fetch(encodedURI)
.then((data) => data.json())
.then((repos) => repos.items)
.catch((error) => {
console.warn(error)
return null
});
}
}
</script>
<script type='text/babel'>
class Loading extends React.Component {
constructor(props) {
super(props);
this.state = {
text: 'Loading'
};
}
componentDidMount() {
const stopper = this.state.text + '...';
this.interval = window.setInterval(() => {
this.state.text === stopper
? this.setState(() => ({ text: 'Loading' }))
: this.setState(prevState => ({ text: prevState.text + '.' }));
}, 300);
}
componentWillUnmount() {
window.clearInterval(this.interval);
}
render() {
return <p>{this.state.text}</p>;
}
}
const Nav = props => {
const languages = ['all', 'javascript', 'ruby', 'python'];
return (
<ul style={{ display: 'flex', flexWrap: 'wrap' }}>
{languages.map((language, i) => (
<li
key={i}
style={{ margin: '30px' }}
onClick={() => props.handleClick(language)}
>
{language}
</li>
))}
</ul>
);
};
class RepoList extends React.Component {
render() {
let repos = this.props.repos;
// Initially I just thought we needed to filter the repos by the user selected
// option.
// if (this.props.filter !== 'all') {
// repos = repos.filter(
// repo =>
// repo.language && repo.language.toLowerCase() == this.props.filter
// );
// }
return (
<ul style={{ display: 'flex', flexWrap: 'wrap' }}>
{repos.map(repo => (
<li key={repo.id} style={{ margin: '30px' }}>
<ul>
<li>
<a href={repo.html_url}>{repo.name}</a>
</li>
<li>@{repo.owner.login}</li>
<li>{repo.stargazers_count} stars</li>
</ul>
</li>
))}
</ul>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
repos: [],
filter: 'all',
loading: true
};
this.setFilter = this.setFilter.bind(this);
console.log('--constructor--');
}
componentDidMount() {
console.log('--componentDidMount--');
this.fetchRepos();
}
componentDidUpdate(prevProps, prevState) {
console.log('--componentDidUpdate--');
if (prevState.filter !== this.state.filter) {
this.setState({
loading: true
});
this.fetchRepos();
}
}
fetchRepos() {
API.fetchPopularRepos(this.state.filter).then(repos => {
console.log('repos', repos);
this.setState({
repos,
loading: false
});
});
}
setFilter(filter) {
console.log('--setFilter--');
this.setState({
filter
});
}
render() {
if (this.state.loading === true) {
return <Loading />;
}
return (
<div>
<Nav handleClick={this.setFilter} />
<h1 style={{ textAlign: 'center' }}>{this.state.filter}</h1>
<RepoList repos={this.state.repos} filter={this.state.filter} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment