From 4c5490df94fee96c1af63b38ef774fa96d516016 Mon Sep 17 00:00:00 2001 From: ta264 Date: Sun, 16 Feb 2020 19:31:03 +0000 Subject: [PATCH] Fixed: Improve performance of Manual Import movie selector --- .../Movie/SelectMovieModalContent.css | 2 +- .../Movie/SelectMovieModalContent.js | 126 +++++++++++++++--- .../Movie/SelectMovieModalContentConnector.js | 53 ++++++-- .../Movie/SelectMovieRow.css | 1 + 4 files changed, 148 insertions(+), 34 deletions(-) diff --git a/frontend/src/InteractiveImport/Movie/SelectMovieModalContent.css b/frontend/src/InteractiveImport/Movie/SelectMovieModalContent.css index fd624f2a0..ba21e920e 100644 --- a/frontend/src/InteractiveImport/Movie/SelectMovieModalContent.css +++ b/frontend/src/InteractiveImport/Movie/SelectMovieModalContent.css @@ -14,7 +14,7 @@ } .scroller { - flex: 1 1 auto; + min-height: 1px; } .footer { diff --git a/frontend/src/InteractiveImport/Movie/SelectMovieModalContent.js b/frontend/src/InteractiveImport/Movie/SelectMovieModalContent.js index a56588d5b..d9173f5a8 100644 --- a/frontend/src/InteractiveImport/Movie/SelectMovieModalContent.js +++ b/frontend/src/InteractiveImport/Movie/SelectMovieModalContent.js @@ -1,6 +1,9 @@ +import _ from 'lodash'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { scrollDirections } from 'Helpers/Props'; +import VirtualTable from 'Components/Table/VirtualTable'; +import VirtualTableRow from 'Components/Table/VirtualTableRow'; import Button from 'Components/Link/Button'; import Scroller from 'Components/Scroller/Scroller'; import TextInput from 'Components/Form/TextInput'; @@ -8,9 +11,13 @@ import ModalContent from 'Components/Modal/ModalContent'; import ModalHeader from 'Components/Modal/ModalHeader'; import ModalBody from 'Components/Modal/ModalBody'; import ModalFooter from 'Components/Modal/ModalFooter'; +import LoadingIndicator from 'Components/Loading/LoadingIndicator'; import SelectMovieRow from './SelectMovieRow'; +import FuseWorker from 'Components/Page/Header/fuse.worker'; import styles from './SelectMovieModalContent.css'; +const workerInstance = new FuseWorker(); + class SelectMovieModalContent extends Component { // @@ -20,15 +27,84 @@ class SelectMovieModalContent extends Component { super(props, context); this.state = { - filter: '' + scroller: null, + filter: '', + showLoading: false, + suggestions: props.items }; } + componentDidMount() { + workerInstance.addEventListener('message', this.onSuggestionsReceived, false); + } + + // + // Control + + setScrollerRef = (ref) => { + this.setState({ scroller: ref }); + } + + rowRenderer = ({ key, rowIndex, style }) => { + const item = this.state.suggestions[rowIndex]; + + return ( + + + + ); + } + // // Listeners onFilterChange = ({ value }) => { - this.setState({ filter: value.toLowerCase() }); + if (value) { + this.setState({ + showLoading: true, + filter: value.toLowerCase() + }); + this.requestSuggestions(value); + } else { + this.setState({ + showLoading: false, + filter: '', + suggestions: this.props.items + }); + this.requestSuggestions.cancel(); + } + } + + requestSuggestions = _.debounce((value) => { + const payload = { + value, + movies: this.props.items + }; + + workerInstance.postMessage(payload); + }, 250); + + onSuggestionsReceived = (message) => { + this.setState((state, props) => { + // this guards against setting a stale set of suggestions returned + // after the filter has been cleared + if (state.filter !== '') { + return { + showLoading: false, + suggestions: message.data.map((suggestion) => suggestion.item) + }; + } + return {}; + }); } // @@ -36,13 +112,16 @@ class SelectMovieModalContent extends Component { render() { const { - items, relativePath, - onMovieSelect, onModalClose } = this.props; - const filter = this.state.filter; + const { + scroller, + filter, + showLoading, + suggestions + } = this.state; return ( @@ -58,29 +137,32 @@ class SelectMovieModalContent extends Component { > - - { - items.map((item) => { - return item.title.toLowerCase().includes(filter) ? - ( - - ) : - null; - }) - } + +
+ { + showLoading || !scroller ? + : + + } + items={suggestions} + isSmallScreen={false} + scroller={scroller} + rowRenderer={this.rowRenderer} + /> + } +
diff --git a/frontend/src/InteractiveImport/Movie/SelectMovieModalContentConnector.js b/frontend/src/InteractiveImport/Movie/SelectMovieModalContentConnector.js index fdb739838..b728d9422 100644 --- a/frontend/src/InteractiveImport/Movie/SelectMovieModalContentConnector.js +++ b/frontend/src/InteractiveImport/Movie/SelectMovieModalContentConnector.js @@ -4,24 +4,55 @@ import { connect } from 'react-redux'; import { createSelector } from 'reselect'; import { updateInteractiveImportItem } from 'Store/Actions/interactiveImportActions'; import createAllMoviesSelector from 'Store/Selectors/createAllMoviesSelector'; +import createDeepEqualSelector from 'Store/Selectors/createDeepEqualSelector'; import SelectMovieModalContent from './SelectMovieModalContent'; -function createMapStateToProps() { +function createCleanMovieSelector() { return createSelector( createAllMoviesSelector(), (items) => { - return { - items: [...items].sort((a, b) => { - if (a.sortTitle < b.sortTitle) { - return -1; - } + return items.map((movie) => { + const { + id, + title, + titleSlug, + sortTitle, + year, + images, + alternateTitles = [] + } = movie; + + return { + id, + title, + titleSlug, + sortTitle, + year, + images, + alternateTitles, + firstCharacter: title.charAt(0).toLowerCase() + }; + }).sort((a, b) => { + if (a.sortTitle < b.sortTitle) { + return -1; + } - if (a.sortTitle > b.sortTitle) { - return 1; - } + if (a.sortTitle > b.sortTitle) { + return 1; + } + + return 0; + }); + } + ); +} - return 0; - }) +function createMapStateToProps() { + return createDeepEqualSelector( + createCleanMovieSelector(), + (movies) => { + return { + items: movies }; } ); diff --git a/frontend/src/InteractiveImport/Movie/SelectMovieRow.css b/frontend/src/InteractiveImport/Movie/SelectMovieRow.css index f84778bb5..6ebc63656 100644 --- a/frontend/src/InteractiveImport/Movie/SelectMovieRow.css +++ b/frontend/src/InteractiveImport/Movie/SelectMovieRow.css @@ -1,4 +1,5 @@ .movie { padding: 8px; + width: 100%; border-bottom: 1px solid $borderColor; }