Lazy loading via awesome component
This commit is contained in:
38
src/js/components/LazyLoadListener.js
Executable file
38
src/js/components/LazyLoadListener.js
Executable file
@ -0,0 +1,38 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
|
||||
export default class LazyLoadListener extends React.Component{
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { loading: false }
|
||||
this.handleScroll = this.handleScroll.bind(this);
|
||||
}
|
||||
|
||||
componentWillMount(){
|
||||
window.addEventListener("scroll", this.handleScroll, false);
|
||||
}
|
||||
|
||||
componentWillUnmount(){
|
||||
window.removeEventListener("scroll", this.handleScroll, false);
|
||||
}
|
||||
|
||||
handleScroll(e){
|
||||
if( (window.innerHeight + window.scrollY) >= document.body.offsetHeight ){
|
||||
if( !this.state.loading ){
|
||||
this.setState({ loading: true })
|
||||
this.props.loadMore();
|
||||
}
|
||||
}else if( this.state.loading ){
|
||||
this.setState({ loading: false })
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
if( this.loading ){
|
||||
return <div className='lazy-loader loading'><div className="content">LOADING</div></div>
|
||||
}else{
|
||||
return <div className='lazy-loader'></div>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -20,11 +20,10 @@ export default class Thumbnail extends React.Component{
|
||||
}
|
||||
|
||||
componentWillReceiveProps( nextProps ){
|
||||
this.mapImageSizes();
|
||||
this.mapImageSizes( nextProps.images );
|
||||
}
|
||||
|
||||
mapImageSizes(){
|
||||
var images = this.props.images;
|
||||
mapImageSizes( images = this.props.images ){
|
||||
var state = this.state;
|
||||
|
||||
if( images.length <= 0 ){
|
||||
|
||||
@ -1,28 +1,4 @@
|
||||
|
||||
/**
|
||||
* Actions and Action Creators
|
||||
**/
|
||||
|
||||
export function setConfig( config ){
|
||||
return {
|
||||
type: 'SPOTIFY_SET_CONFIG',
|
||||
config: config
|
||||
}
|
||||
}
|
||||
|
||||
export function connect(){
|
||||
return {
|
||||
type: 'SPOTIFY_CONNECTING'
|
||||
}
|
||||
}
|
||||
|
||||
export function disconnect(){
|
||||
return {
|
||||
type: 'SPOTIFY_DISCONNECT'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send an ajax request to the Spotify API
|
||||
*
|
||||
@ -37,18 +13,22 @@ const sendRequest = ( dispatch, getState, endpoint, method = 'GET', data = false
|
||||
return new Promise( (resolve, reject) => {
|
||||
getToken( dispatch, getState )
|
||||
.then( response => {
|
||||
|
||||
var url = 'https://api.spotify.com/v1/'+endpoint
|
||||
if( endpoint.startsWith('https://api.spotify.com/') ) url = endpoint;
|
||||
|
||||
$.ajax({
|
||||
method: method,
|
||||
cache: true,
|
||||
url: 'https://api.spotify.com/v1/'+endpoint,
|
||||
url: url,
|
||||
headers: {
|
||||
Authorization: 'Bearer '+ response
|
||||
},
|
||||
data: data
|
||||
}).then(
|
||||
response => resolve(response),
|
||||
error => {
|
||||
console.error('Could not send request to '+endpoint, error, data)
|
||||
(xhr, status, error) => {
|
||||
console.error( endpoint+' failed', xhr.responseText)
|
||||
reject(error)
|
||||
}
|
||||
)
|
||||
@ -58,24 +38,6 @@ const sendRequest = ( dispatch, getState, endpoint, method = 'GET', data = false
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle authorization process
|
||||
**/
|
||||
|
||||
export function startAuthorization(){
|
||||
return { type: 'SPOTIFY_START_AUTHORIZATION' }
|
||||
}
|
||||
|
||||
export function authorizationGranted( data ){
|
||||
data.token_expiry = new Date().getTime() + data.expires_in;
|
||||
return { type: 'SPOTIFY_AUTHORIZATION_GRANTED', data: data }
|
||||
}
|
||||
|
||||
export function authorizationRevoked(){
|
||||
return { type: 'SPOTIFY_AUTHORIZATION_REVOKED' }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check an access token validity
|
||||
*
|
||||
@ -154,6 +116,48 @@ function refreshToken( dispatch, getState ){
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Actions and Action Creators
|
||||
**/
|
||||
|
||||
export function setConfig( config ){
|
||||
return {
|
||||
type: 'SPOTIFY_SET_CONFIG',
|
||||
config: config
|
||||
}
|
||||
}
|
||||
|
||||
export function connect(){
|
||||
return {
|
||||
type: 'SPOTIFY_CONNECTING'
|
||||
}
|
||||
}
|
||||
|
||||
export function disconnect(){
|
||||
return {
|
||||
type: 'SPOTIFY_DISCONNECT'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle authorization process
|
||||
**/
|
||||
|
||||
export function startAuthorization(){
|
||||
return { type: 'SPOTIFY_START_AUTHORIZATION' }
|
||||
}
|
||||
|
||||
export function authorizationGranted( data ){
|
||||
data.token_expiry = new Date().getTime() + data.expires_in;
|
||||
return { type: 'SPOTIFY_AUTHORIZATION_GRANTED', data: data }
|
||||
}
|
||||
|
||||
export function authorizationRevoked(){
|
||||
return { type: 'SPOTIFY_AUTHORIZATION_REVOKED' }
|
||||
}
|
||||
|
||||
export function refreshingToken(){
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: 'SPOTIFY_TOKEN_REFRESHING' });
|
||||
@ -337,7 +341,7 @@ export function getLibraryArtists(){
|
||||
.then( response => {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_LIBRARY_ARTISTS_LOADED',
|
||||
data: response
|
||||
data: response.artists
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -450,7 +454,7 @@ export function getCategoryPlaylists( id ){
|
||||
}
|
||||
|
||||
export function getNewReleases(){
|
||||
return (dispatch, getState) => {
|
||||
return (dispatch, getState) => {
|
||||
|
||||
dispatch({ type: 'SPOTIFY_NEW_RELEASES_LOADED', data: false });
|
||||
|
||||
@ -461,6 +465,18 @@ export function getNewReleases(){
|
||||
data: response.albums
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getURL( url, action_name ){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest( dispatch, getState, url )
|
||||
.then( response => {
|
||||
dispatch({
|
||||
type: action_name,
|
||||
data: response
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -68,15 +68,39 @@ export default function reducer(spotify = {}, action){
|
||||
case 'SPOTIFY_ARTIST_ALBUMS_LOADED':
|
||||
return Object.assign({}, spotify, { artist_albums: action.data });
|
||||
|
||||
case 'SPOTIFY_ARTIST_ALBUMS_LOADED_MORE':
|
||||
return Object.assign({}, spotify, { artist_albums: {
|
||||
href: action.data.href,
|
||||
next: action.data.next,
|
||||
previous: action.data.previous,
|
||||
items: [ ...spotify.artist_albums.items, ...action.data.items ]
|
||||
}});
|
||||
|
||||
case 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED':
|
||||
return Object.assign({}, spotify, { library_playlists: action.data });
|
||||
|
||||
case 'SPOTIFY_LIBRARY_ARTISTS_LOADED':
|
||||
return Object.assign({}, spotify, { library_artists: action.data });
|
||||
|
||||
case 'SPOTIFY_LIBRARY_ARTISTS_LOADED_MORE':
|
||||
return Object.assign({}, spotify, { library_artists: {
|
||||
href: action.data.artists.href,
|
||||
next: action.data.artists.next,
|
||||
previous: action.data.artists.previous,
|
||||
items: [ ...spotify.library_artists.items, ...action.data.artists.items ]
|
||||
}});
|
||||
|
||||
case 'SPOTIFY_LIBRARY_ALBUMS_LOADED':
|
||||
return Object.assign({}, spotify, { library_albums: action.data });
|
||||
|
||||
case 'SPOTIFY_LIBRARY_ALBUMS_LOADED_MORE':
|
||||
return Object.assign({}, spotify, { library_albums: {
|
||||
href: action.data.href,
|
||||
next: action.data.next,
|
||||
previous: action.data.previous,
|
||||
items: [ ...spotify.library_albums.items, ...action.data.items ]
|
||||
}});
|
||||
|
||||
case 'SPOTIFY_LIBRARY_TRACKS_LOADED':
|
||||
return Object.assign({}, spotify, { library_tracks: action.data });
|
||||
|
||||
@ -92,9 +116,25 @@ export default function reducer(spotify = {}, action){
|
||||
case 'SPOTIFY_CATEGORY_PLAYLISTS_LOADED':
|
||||
return Object.assign({}, spotify, { category_playlists: action.data });
|
||||
|
||||
case 'SPOTIFY_CATEGORY_PLAYLISTS_LOADED_MORE':
|
||||
return Object.assign({}, spotify, { category_playlists: {
|
||||
href: action.data.href,
|
||||
next: action.data.next,
|
||||
previous: action.data.previous,
|
||||
items: [ ...spotify.category_playlists.items, ...action.data.items ]
|
||||
}});
|
||||
|
||||
case 'SPOTIFY_NEW_RELEASES_LOADED':
|
||||
return Object.assign({}, spotify, { new_releases: action.data });
|
||||
|
||||
case 'SPOTIFY_NEW_RELEASES_LOADED_MORE':
|
||||
return Object.assign({}, spotify, { new_releases: {
|
||||
href: action.data.albums.href,
|
||||
next: action.data.albums.next,
|
||||
previous: action.data.albums.previous,
|
||||
items: [ ...spotify.new_releases.items, ...action.data.albums.items ]
|
||||
}});
|
||||
|
||||
default:
|
||||
return spotify
|
||||
}
|
||||
|
||||
@ -16,4 +16,11 @@ export function hideContextMenu(){
|
||||
}
|
||||
}
|
||||
|
||||
export function lazyLoading( start ){
|
||||
return {
|
||||
type: 'UI_LAZY_LOADING',
|
||||
start: start
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -16,6 +16,9 @@ export default function reducer(ui = {}, action){
|
||||
case 'UI_HIDE_CONTEXT_MENU':
|
||||
return Object.assign({}, ui, { context_menu: { show: false } });
|
||||
|
||||
case 'UI_LAZY_LOADING':
|
||||
return Object.assign({}, ui, { lazy_loading: action.start });
|
||||
|
||||
default:
|
||||
return ui
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import React, { PropTypes } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
|
||||
import LazyLoadListener from '../components/LazyLoadListener'
|
||||
import Header from '../components/Header'
|
||||
import TrackList from '../components/TrackList'
|
||||
import AlbumGrid from '../components/AlbumGrid'
|
||||
@ -30,6 +31,11 @@ class Artist extends React.Component{
|
||||
}
|
||||
}
|
||||
|
||||
loadMore(){
|
||||
if( !this.props.spotify.artist_albums || !this.props.spotify.artist_albums.next ) return
|
||||
this.props.spotifyActions.getURL( this.props.spotify.artist_albums.next, 'SPOTIFY_ARTIST_ALBUMS_LOADED_MORE' );
|
||||
}
|
||||
|
||||
render(){
|
||||
if( this.props.spotify.artist ){
|
||||
return (
|
||||
@ -58,6 +64,7 @@ class Artist extends React.Component{
|
||||
|
||||
<h4 className="left-padding">Albums</h4>
|
||||
{ this.props.spotify.artist_albums ? <AlbumGrid className="no-top-padding" albums={ this.props.spotify.artist_albums.items } /> : null }
|
||||
<LazyLoadListener loadMore={ () => this.loadMore() }/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import { bindActionCreators } from 'redux'
|
||||
|
||||
import Header from '../../components/Header'
|
||||
import PlaylistGrid from '../../components/PlaylistGrid'
|
||||
import LazyLoadListener from '../../components/LazyLoadListener'
|
||||
|
||||
import * as spotifyActions from '../../services/spotify/actions'
|
||||
|
||||
@ -26,6 +27,11 @@ class DiscoverCategory extends React.Component{
|
||||
}
|
||||
}
|
||||
|
||||
loadMore(){
|
||||
if( !this.props.spotify.new_releases || !this.props.spotify.new_releases.next ) return
|
||||
this.props.spotifyActions.getURL( this.props.spotify.new_releases.next, 'SPOTIFY_NEW_RELEASES_LOADED_MORE' );
|
||||
}
|
||||
|
||||
render(){
|
||||
if( !this.props.spotify.category ) return null;
|
||||
|
||||
@ -33,6 +39,7 @@ class DiscoverCategory extends React.Component{
|
||||
<div className="view discover-categories-view">
|
||||
<Header icon="grid" title={this.props.spotify.category.name} />
|
||||
{ this.props.spotify.category_playlists ? <PlaylistGrid playlists={this.props.spotify.category_playlists.items} /> : null }
|
||||
<LazyLoadListener loadMore={ () => this.loadMore() }/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -5,7 +5,9 @@ import { bindActionCreators } from 'redux'
|
||||
|
||||
import Header from '../../components/Header'
|
||||
import AlbumGrid from '../../components/AlbumGrid'
|
||||
import LazyLoadListener from '../../components/LazyLoadListener'
|
||||
|
||||
import * as uiActions from '../../services/ui/actions'
|
||||
import * as spotifyActions from '../../services/spotify/actions'
|
||||
|
||||
class DiscoverNewReleases extends React.Component{
|
||||
@ -14,16 +16,21 @@ class DiscoverNewReleases extends React.Component{
|
||||
super(props);
|
||||
}
|
||||
|
||||
// on render
|
||||
componentDidMount(){
|
||||
this.props.spotifyActions.getNewReleases();
|
||||
}
|
||||
|
||||
loadMore(){
|
||||
if( !this.props.spotify.new_releases || !this.props.spotify.new_releases.next ) return
|
||||
this.props.spotifyActions.getURL( this.props.spotify.new_releases.next, 'SPOTIFY_NEW_RELEASES_LOADED_MORE' );
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div className="view discover-new-releases-view">
|
||||
<Header icon="leaf" title="New Releases" />
|
||||
{ this.props.spotify.new_releases ? <AlbumGrid albums={this.props.spotify.new_releases.items} /> : null }
|
||||
<LazyLoadListener loadMore={ () => this.loadMore() }/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -42,6 +49,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import { Link } from 'react-router'
|
||||
|
||||
import AlbumGrid from '../../components/AlbumGrid'
|
||||
import Header from '../../components/Header'
|
||||
import LazyLoadListener from '../../components/LazyLoadListener'
|
||||
|
||||
import * as mopidyActions from '../../services/mopidy/actions'
|
||||
import * as spotifyActions from '../../services/spotify/actions'
|
||||
@ -16,11 +17,15 @@ class LibraryAlbums extends React.Component{
|
||||
super(props);
|
||||
}
|
||||
|
||||
// on render
|
||||
componentDidMount(){
|
||||
this.props.spotifyActions.getLibraryAlbums();
|
||||
}
|
||||
|
||||
loadMore(){
|
||||
if( !this.props.spotify.library_albums || !this.props.spotify.library_albums.next ) return
|
||||
this.props.spotifyActions.getURL( this.props.spotify.library_albums.next, 'SPOTIFY_LIBRARY_ALBUMS_LOADED_MORE' );
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div className="view library-albums-view">
|
||||
@ -29,6 +34,7 @@ class LibraryAlbums extends React.Component{
|
||||
title="My albums"
|
||||
/>
|
||||
{ this.props.spotify.library_albums ? <AlbumGrid albums={this.props.spotify.library_albums.items} /> : null }
|
||||
<LazyLoadListener loadMore={ () => this.loadMore() }/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
import { Link } from 'react-router'
|
||||
|
||||
import LazyLoadListener from '../../components/LazyLoadListener'
|
||||
import Header from '../../components/Header'
|
||||
import ArtistGrid from '../../components/ArtistGrid'
|
||||
|
||||
@ -21,6 +22,11 @@ class LibraryArtists extends React.Component{
|
||||
this.props.spotifyActions.getLibraryArtists();
|
||||
}
|
||||
|
||||
loadMore(){
|
||||
if( !this.props.spotify.library_artists || !this.props.spotify.library_artists.next ) return
|
||||
this.props.spotifyActions.getURL( this.props.spotify.library_artists.next, 'SPOTIFY_LIBRARY_ARTISTS_LOADED_MORE' );
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div className="view library-artists-view">
|
||||
@ -28,7 +34,8 @@ class LibraryArtists extends React.Component{
|
||||
icon="mic"
|
||||
title="My artists"
|
||||
/>
|
||||
{ this.props.spotify.library_artists ? <ArtistGrid artists={this.props.spotify.library_artists.artists.items} /> : null }
|
||||
{ this.props.spotify.library_artists ? <ArtistGrid artists={this.props.spotify.library_artists.items} /> : null }
|
||||
<LazyLoadListener loadMore={ () => this.loadMore() }/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
@import 'global/reset';
|
||||
@import 'global/forms';
|
||||
|
||||
@import 'components/lazy-load-listener';
|
||||
@import 'components/context-menu';
|
||||
@import 'components/images';
|
||||
@import 'components/icon';
|
||||
|
||||
9
src/scss/components/_lazy-load-listener.scss
Executable file
9
src/scss/components/_lazy-load-listener.scss
Executable file
@ -0,0 +1,9 @@
|
||||
|
||||
.lazy-loader {
|
||||
height: 50px;
|
||||
color: $light_grey;
|
||||
|
||||
&.loading {
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user