From 8d39af06e39e3c3c0ca3aacb102275eee61d9bc7 Mon Sep 17 00:00:00 2001 From: james hadfield Date: Thu, 19 Nov 2020 15:25:14 +1300 Subject: [PATCH] Improve performance of sidebar filter UI The previous implementation of the sidebar filtering was slow to respond to keystrokes for large datasets. This was because of two implementation decisions: (i) the list of available filters was computed upon every key-stroke and (ii) the matching algorithm was run against this. A subsequent key-stroke wouldn't appear until both steps had completed. Here we improve (i) by precomputing the options at component render time, and improve (ii) by debouncing the matching algorithm and not ignoring accents. (Profiling indicated that the stripping of accents took a lot of time.) By using an Async React Select component we get a spinner UI to indicate that the result of the matching algorithm is being awaited. --- src/components/controls/filter.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/controls/filter.js b/src/components/controls/filter.js index 90d74f3ac..2fc41c2cb 100644 --- a/src/components/controls/filter.js +++ b/src/components/controls/filter.js @@ -1,11 +1,13 @@ import React from "react"; import { connect } from "react-redux"; -import Select from "react-select/lib/Select"; +import Async from "react-select/lib/Async"; +import { debounce } from 'lodash'; import { controlsWidth, isValueValid, strainSymbol} from "../../util/globals"; import { applyFilter } from "../../actions/tree"; import { FilterBadge } from "../info/filterBadge"; import { SidebarSubtitle } from "./styles"; +const DEBOUNCE_TIME = 200; /** * is a (keyboard)-typing based search box intended to @@ -83,16 +85,21 @@ class FilterData extends React.Component { }); } render() { + // options only need to be calculated a single time per render, and by adding a debounce + // to `loadOptions` we don't slow things down by comparing queries to a large number of options + const options = this.makeOptions(); + const loadOptions = debounce((input, callback) => callback(null, {options}), DEBOUNCE_TIME); const styles = this.getStyles(); const inUseFilters = this.summariseFilters(); return (
-