Selectors not properly memoized for Library views, renders every second (track position changing)
This commit is contained in:
@ -56,6 +56,18 @@ class LibraryAlbums extends React.Component {
|
||||
this.getGoogleLibrary();
|
||||
this.getSpotifyLibrary();
|
||||
}
|
||||
/*
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
Object.entries(this.props).forEach(([key, val]) =>
|
||||
prevProps[key] !== val && console.log(`Prop '${key}' changed`)
|
||||
);
|
||||
if (this.state) {
|
||||
Object.entries(this.state).forEach(([key, val]) =>
|
||||
prevState[key] !== val && console.log(`State '${key}' changed`)
|
||||
);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
componentDidUpdate = ({ source: prevSource }) => {
|
||||
const { source } = this.props;
|
||||
@ -67,40 +79,6 @@ class LibraryAlbums extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate = ({
|
||||
albums: prevAlbums,
|
||||
sort: prevSort,
|
||||
sort_reverse: prevSortReverse,
|
||||
source: prevSource,
|
||||
view: prevView,
|
||||
},
|
||||
{
|
||||
filter: prevFilter,
|
||||
limit: prevLimit,
|
||||
}) => {
|
||||
const {
|
||||
albums,
|
||||
sort,
|
||||
sort_reverse,
|
||||
source,
|
||||
view,
|
||||
} = this.props;
|
||||
const {
|
||||
filter,
|
||||
limit,
|
||||
} = this.state;
|
||||
|
||||
if (prevAlbums.length !== albums.length) return true;
|
||||
if (prevSource !== source) return true;
|
||||
if (prevSort !== sort) return true;
|
||||
if (prevSortReverse !== sort_reverse) return true;
|
||||
if (prevView !== view) return true;
|
||||
if (prevFilter !== filter) return true;
|
||||
if (prevLimit !== limit) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
onRefresh = () => {
|
||||
const { uiActions: { hideContextMenu } } = this.props;
|
||||
|
||||
@ -216,6 +194,8 @@ class LibraryAlbums extends React.Component {
|
||||
} = this.state;
|
||||
let { albums } = this.props;
|
||||
|
||||
console.log('library albums render', loading, albums.length);
|
||||
|
||||
if (loading) {
|
||||
return <Loader body loading />;
|
||||
}
|
||||
@ -414,15 +394,15 @@ const mapStateToProps = (state) => {
|
||||
];
|
||||
|
||||
return {
|
||||
mopidy_uri_schemes: state.mopidy.uri_schemes,
|
||||
loading: loadingSelector(state),
|
||||
mopidy_uri_schemes: state.mopidy.uri_schemes,
|
||||
albums,
|
||||
google_available: (state.mopidy.uri_schemes && state.mopidy.uri_schemes.includes('gmusic:')),
|
||||
spotify_available: state.spotify.access_token,
|
||||
view: state.ui.library_albums_view,
|
||||
source,
|
||||
sort: (state.ui.library_albums_sort ? state.ui.library_albums_sort : null),
|
||||
sort_reverse: (state.ui.library_albums_sort_reverse ? state.ui.library_albums_sort_reverse : false),
|
||||
sort: state.ui.library_albums_sort,
|
||||
sort_reverse: state.ui.library_albums_sort_reverse,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -331,7 +331,7 @@ class LibraryArtists extends React.Component {
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
const source = state.ui.library_albums_source ? state.ui.library_albums_source : 'all';
|
||||
const source = state.ui.library_artists_source || 'all';
|
||||
const loadingSelector = makeLoadingSelector(['(.*):library:artists']);
|
||||
const spotifyLibrarySelector = makeLibrarySelector('spotify:library:artists');
|
||||
const googleLibrarySelector = makeLibrarySelector('google:library:artists');
|
||||
|
||||
@ -19,6 +19,7 @@ import { I18n, i18n } from '../../locale';
|
||||
import { collate } from '../../util/format';
|
||||
import { isLoading } from '../../util/helpers';
|
||||
import Loader from '../../components/Loader';
|
||||
import { makeLibrarySelector, makeLoadingSelector } from '../../util/selectors';
|
||||
|
||||
class LibraryPlaylists extends React.Component {
|
||||
constructor(props) {
|
||||
@ -133,29 +134,22 @@ class LibraryPlaylists extends React.Component {
|
||||
|
||||
renderView = () => {
|
||||
const {
|
||||
spotify_library,
|
||||
mopidy_library,
|
||||
items,
|
||||
sort,
|
||||
sort_reverse,
|
||||
view,
|
||||
source,
|
||||
load_queue,
|
||||
loading,
|
||||
} = this.props;
|
||||
const {
|
||||
filter,
|
||||
limit,
|
||||
} = this.state;
|
||||
let { playlists } = this.props;
|
||||
|
||||
if (isLoading(load_queue, ['(.*):library:playlists'])) {
|
||||
if (loading) {
|
||||
return <Loader body loading />;
|
||||
}
|
||||
|
||||
let playlists = [
|
||||
...(source === 'all' || source === 'spotify' ? collate(spotify_library, { items }).items : []),
|
||||
...(source === 'all' || source === 'local' ? collate(mopidy_library, { items }).items : []),
|
||||
];
|
||||
|
||||
if (sort) {
|
||||
playlists = sortItems(playlists, sort, sort_reverse);
|
||||
}
|
||||
@ -204,7 +198,19 @@ class LibraryPlaylists extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
render = () => {
|
||||
const {
|
||||
uiActions,
|
||||
spotify_available,
|
||||
source,
|
||||
sort,
|
||||
sort_reverse,
|
||||
view,
|
||||
} = this.props;
|
||||
const {
|
||||
filter,
|
||||
} = this.state;
|
||||
|
||||
const source_options = [
|
||||
{
|
||||
value: 'all',
|
||||
@ -216,7 +222,7 @@ class LibraryPlaylists extends React.Component {
|
||||
},
|
||||
];
|
||||
|
||||
if (this.props.spotify_available) {
|
||||
if (spotify_available) {
|
||||
source_options.push({
|
||||
value: 'spotify',
|
||||
label: i18n('services.spotify.title'),
|
||||
@ -268,34 +274,34 @@ class LibraryPlaylists extends React.Component {
|
||||
const options = (
|
||||
<span>
|
||||
<FilterField
|
||||
initialValue={this.state.filter}
|
||||
initialValue={filter}
|
||||
handleChange={(value) => this.setState({ filter: value })}
|
||||
onSubmit={e => this.props.uiActions.hideContextMenu()}
|
||||
onSubmit={() => uiActions.hideContextMenu()}
|
||||
/>
|
||||
<DropdownField
|
||||
icon="swap_vert"
|
||||
name={i18n('fields.sort')}
|
||||
value={this.props.sort}
|
||||
value={sort}
|
||||
valueAsLabel
|
||||
options={sort_options}
|
||||
selected_icon={this.props.sort ? (this.props.sort_reverse ? 'keyboard_arrow_up' : 'keyboard_arrow_down') : null}
|
||||
handleChange={(value) => { this.setSort(value); this.props.uiActions.hideContextMenu(); }}
|
||||
selected_icon={sort ? (sort_reverse ? 'keyboard_arrow_up' : 'keyboard_arrow_down') : null}
|
||||
handleChange={(value) => { this.setSort(value); uiActions.hideContextMenu(); }}
|
||||
/>
|
||||
<DropdownField
|
||||
icon="visibility"
|
||||
name={i18n('fields.view')}
|
||||
valueAsLabel
|
||||
value={this.props.view}
|
||||
value={view}
|
||||
options={view_options}
|
||||
handleChange={(value) => { this.props.uiActions.set({ library_playlists_view: value }); this.props.uiActions.hideContextMenu(); }}
|
||||
handleChange={(value) => { uiActions.set({ library_playlists_view: value }); uiActions.hideContextMenu(); }}
|
||||
/>
|
||||
<DropdownField
|
||||
icon="cloud"
|
||||
name={i18n('fields.source')}
|
||||
valueAsLabel
|
||||
value={this.props.source}
|
||||
value={source}
|
||||
options={source_options}
|
||||
handleChange={(value) => { this.props.uiActions.set({ library_playlists_source: value }); this.props.uiActions.hideContextMenu(); }}
|
||||
handleChange={(value) => { uiActions.set({ library_playlists_source: value }); uiActions.hideContextMenu(); }}
|
||||
/>
|
||||
<Button
|
||||
to="/playlist/create"
|
||||
@ -319,7 +325,7 @@ class LibraryPlaylists extends React.Component {
|
||||
|
||||
return (
|
||||
<div className="view library-playlists-view">
|
||||
<Header options={options} uiActions={this.props.uiActions}>
|
||||
<Header options={options} uiActions={uiActions}>
|
||||
<Icon name="queue_music" type="material" />
|
||||
<I18n path="library.playlists.title" />
|
||||
</Header>
|
||||
@ -330,20 +336,29 @@ class LibraryPlaylists extends React.Component {
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
const source = state.ui.library_playlists_source || 'all';
|
||||
const loadingSelector = makeLoadingSelector(['(.*):library:playlists']);
|
||||
const spotifyLibrarySelector = makeLibrarySelector('spotify:library:playlists');
|
||||
const googleLibrarySelector = makeLibrarySelector('google:library:playlists');
|
||||
const mopidyLibrarySelector = makeLibrarySelector('mopidy:library:playlists');
|
||||
|
||||
const playlists = [
|
||||
...(source === 'all' || source === 'spotify' ? spotifyLibrarySelector(state) : []),
|
||||
...(source === 'all' || source === 'google' ? googleLibrarySelector(state) : []),
|
||||
...(source === 'all' || source === 'local' ? mopidyLibrarySelector(state) : []),
|
||||
];
|
||||
|
||||
return {
|
||||
slim_mode: state.ui.slim_mode,
|
||||
mopidy_uri_schemes: state.mopidy.uri_schemes,
|
||||
spotify_available: state.spotify.access_token,
|
||||
items: state.core.items,
|
||||
mopidy_library: state.core.libraries['mopidy:library:playlists'] || { items_uris: [] },
|
||||
spotify_library: state.core.libraries['spotify:library:playlists'] || { items_uris: [] },
|
||||
load_queue: state.ui.load_queue,
|
||||
playlists,
|
||||
loading: loadingSelector(state),
|
||||
source,
|
||||
me_id: (state.spotify.me ? state.spotify.me.id : false),
|
||||
view: state.ui.library_playlists_view,
|
||||
source: (state.ui.library_playlists_source ? state.ui.library_playlists_source : 'all'),
|
||||
sort: (state.ui.library_playlists_sort ? state.ui.library_playlists_sort : null),
|
||||
sort_reverse: (state.ui.library_playlists_sort_reverse ? state.ui.library_playlists_sort_reverse : false),
|
||||
playlists: state.core.playlists,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user