React
by Turi S
HTML
<div id="app"></div>
<!-- https://itunes.apple.com/us/rss/topalbums/limit=25/json -->
<!--
Album title
Artist Name
Price
Release date
-->
CSS
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
line-height: 1.6;
}
h1 {
text-align: center;
font-size: 200%;
font-weight: bold;
margin-bottom: 1em;
position: relative;
z-index: 10;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
text-align: center;
}
.AlbumList {
display: inline-block;
min-height: 100vh;
}
.Album {
display: flex;
margin-bottom: 1em;
text-align: left;
align-items: center;
border-radius: 3px;
box-shadow: 0 1px 6px -3px black;
}
.Album__body {
margin-left: 2em;
}
.Album h2 {
font-weight: bold;
font-size: 110%;
}
.Album__artist {
font-style: italic;
}
.Album__price {
font-weight: bold;
}
.Album__release {
color: rgb(171,193,208);
font-size: 90%;
}
.Album img { display: block; }
@media (max-width: 500px) {
.Album {
flex-direction: column;
align-items: stretch;
border-bottom: 1px solid lightgray;
margin-bottom: 2em;
}
.Album__body {
margin-left: 0;
margin: 1em;
}
.Album__image-wrap {
background: #000000;
}
.Album img {
margin: 0 auto;
}
}
.Loading {
position: fixed;
top: 0; left: 0;
width: 100vw; height: 100vh;
background: rgba(255,255,255,.9);
display: flex;
align-items: center;
justify-content: center;
}
React
class AlbumApp extends React.Component {
constructor(props) {
super(props)
this.state = {albums: null, isLoading: true, limit: 25};
}
componentDidMount() {
this.getAlbumData(this.state.limit, true);
}
getAlbumData(limit, skipInitialState = false) {
if (!skipInitialState) {
this.setState({isLoading: true, limit});
}
const curFetchProm = this.fetchProm = fetch(`https://itunes.apple.com/us/rss/topalbums/limit=${limit}/json`);
curFetchProm
.then(res => res.json())
.then(res => delay(res, 3000))
.then(json => {
if (curFetchProm !== this.fetchProm) return;
console.log('fetch finished');
this.setState({
albums: json.feed.entry,
isLoading: false
})
})
}
render() {
const {albums, isLoading, limit} = this.state;
return (
<div className="AlbumList">
<h1>
Top{' '}
<select value={limit} onChange={
e => this.getAlbumData(e.target.value)
}>
<option value="2">2</option>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
</select>{' '}
iTunes Albums
</h1>
{albums && albums.map((album, i) =>
<Album
key={album.id.attributes['im:id']}
data={album}
rank={i+1}
/>
)}
{isLoading && <Loading />}
</div>
)
}
}
ReactDOM.render(<AlbumApp />, document.querySelector("#app"))
function Album({rank, data}) {
return (
<article className="Album">
<div className="Album__image-wrap">
<img className="Album__artwork" src={data['im:image'][2].label} alt="Album artwork" />
</div>
<div className="Album__body">
<h2>{rank}. {data['im:name'].label}</h2>
<div...