diff --git a/lib/selectors/calendar-selectors.js b/lib/selectors/calendar-selectors.js --- a/lib/selectors/calendar-selectors.js +++ b/lib/selectors/calendar-selectors.js @@ -1,32 +1,26 @@ // @flow -import { createSelector } from 'reselect'; +import * as React from 'react'; import { rawEntryInfoWithinActiveRange } from '../shared/entry-utils'; import SearchIndex from '../shared/search-index'; import { threadInFilterList } from '../shared/thread-utils'; -import type { RawEntryInfo, CalendarQuery } from '../types/entry-types'; -import { type FilterThreadInfo } from '../types/filter-types'; -import type { BaseAppState } from '../types/redux-types'; -import type { ThreadInfo } from '../types/thread-types'; +import type { FilterThreadInfo } from '../types/filter-types'; import { values } from '../utils/objects'; +import { useSelector } from '../utils/redux-utils'; import { currentCalendarQuery } from './nav-selectors'; import { threadInfoSelector } from './thread-selectors'; -const filterThreadInfos: ( - state: BaseAppState<*>, -) => ( +function useFilterThreadInfos( calendarActive: boolean, -) => $ReadOnlyArray = createSelector( - threadInfoSelector, - currentCalendarQuery, - (state: BaseAppState<*>) => state.entryStore.entryInfos, - ( - threadInfos: { +[id: string]: ThreadInfo }, - calendarQueryFunc: (calendarActive: boolean) => CalendarQuery, - rawEntryInfos: { +[id: string]: RawEntryInfo }, - ) => (calendarActive: boolean) => { - const calendarQuery = calendarQueryFunc(calendarActive); +): $ReadOnlyArray { + const threadInfos = useSelector(threadInfoSelector); + const rawEntryInfos = useSelector(state => state.entryStore.entryInfos); + + const calendarQueryFunc = useSelector(currentCalendarQuery); + const calendarQuery = calendarQueryFunc(calendarActive); + + return React.useMemo(() => { const result: { [threadID: string]: FilterThreadInfo } = {}; for (const entryID in rawEntryInfos) { const rawEntryInfo = rawEntryInfos[entryID]; @@ -60,26 +54,19 @@ (first: FilterThreadInfo, second: FilterThreadInfo) => second.numVisibleEntries - first.numVisibleEntries, ); - }, -); + }, [threadInfos, rawEntryInfos, calendarQuery]); +} -const filterThreadSearchIndex: ( - state: BaseAppState<*>, -) => (calendarActive: boolean) => SearchIndex = createSelector( - filterThreadInfos, - ( - threadInfoFunc: ( - calendarActive: boolean, - ) => $ReadOnlyArray, - ) => (calendarActive: boolean) => { - const threadInfos = threadInfoFunc(calendarActive); +function useFilterThreadSearchIndex(calendarActive: boolean): SearchIndex { + const threadInfos = useFilterThreadInfos(calendarActive); + return React.useMemo(() => { const searchIndex = new SearchIndex(); for (const filterThreadInfo of threadInfos) { const { threadInfo } = filterThreadInfo; searchIndex.addEntry(threadInfo.id, threadInfo.uiName); } return searchIndex; - }, -); + }, [threadInfos]); +} -export { filterThreadInfos, filterThreadSearchIndex }; +export { useFilterThreadInfos, useFilterThreadSearchIndex }; diff --git a/web/calendar/filter-panel.react.js b/web/calendar/filter-panel.react.js --- a/web/calendar/filter-panel.react.js +++ b/web/calendar/filter-panel.react.js @@ -33,15 +33,15 @@ import ThreadSettingsModal from '../modals/threads/settings/thread-settings-modal.react'; import { useSelector } from '../redux/redux-utils'; import { - webFilterThreadInfos, - webFilterThreadSearchIndex, + useFilterThreadInfos, + useFilterThreadSearchIndex, } from '../selectors/calendar-selectors'; import { MagnifyingGlass } from '../vectors.react'; import css from './filter-panel.css'; type Props = { - +filterThreadInfos: () => $ReadOnlyArray, - +filterThreadSearchIndex: () => SearchIndex, + +filterThreadInfos: $ReadOnlyArray, + +filterThreadSearchIndex: SearchIndex, +filteredThreadIDs: ?$ReadOnlySet, +includeDeleted: boolean, +dispatch: Dispatch, @@ -69,7 +69,7 @@ render() { const filterThreadInfos = this.state.query ? this.state.searchResults - : this.props.filterThreadInfos(); + : this.props.filterThreadInfos; let filters = []; if (!this.state.query || filterThreadInfos.length > 0) { @@ -154,8 +154,7 @@ return; } else if (!selectedThreadIDs) { // No thread filter exists and thread is being removed - newThreadIDs = this.props - .filterThreadInfos() + newThreadIDs = this.props.filterThreadInfos .map(filterThreadInfo => filterThreadInfo.threadInfo.id) .filter(id => id !== threadID); } else if (selectedThreadIDs.has(threadID) && value) { @@ -169,7 +168,7 @@ return; } else if ( selectedThreadIDs.size + 1 === - this.props.filterThreadInfos().length + this.props.filterThreadInfos.length ) { // Thread filter exists and thread being added is the only one missing newThreadIDs = null; @@ -210,13 +209,11 @@ onChangeQuery = (event: SyntheticEvent) => { const query = event.currentTarget.value; - const searchIndex = this.props.filterThreadSearchIndex(); + const searchIndex = this.props.filterThreadSearchIndex; const resultIDs = new Set(searchIndex.getSearchResults(query)); - const results = this.props - .filterThreadInfos() - .filter(filterThreadInfo => - resultIDs.has(filterThreadInfo.threadInfo.id), - ); + const results = this.props.filterThreadInfos.filter(filterThreadInfo => + resultIDs.has(filterThreadInfo.threadInfo.id), + ); this.setState({ query, searchResults: results, collapsed: false }); }; @@ -365,8 +362,8 @@ const ConnectedFilterPanel: React.ComponentType<{}> = React.memo<{}>( function ConnectedFilterPanel(): React.Node { const filteredThreadIDs = useSelector(filteredThreadIDsSelector); - const filterThreadInfos = useSelector(webFilterThreadInfos); - const filterThreadSearchIndex = useSelector(webFilterThreadSearchIndex); + const filterThreadInfos = useFilterThreadInfos(); + const filterThreadSearchIndex = useFilterThreadSearchIndex(); const includeDeleted = useSelector(includeDeletedSelector); const dispatch = useDispatch(); const modalContext = useModalContext(); diff --git a/web/selectors/calendar-selectors.js b/web/selectors/calendar-selectors.js --- a/web/selectors/calendar-selectors.js +++ b/web/selectors/calendar-selectors.js @@ -1,38 +1,22 @@ // @flow -import { createSelector } from 'reselect'; - import { - filterThreadInfos, - filterThreadSearchIndex, + useFilterThreadInfos as baseUseFilterThreadInfos, + useFilterThreadSearchIndex as baseUseFilterThreadSearchIndex, } from 'lib/selectors/calendar-selectors'; import type SearchIndex from 'lib/shared/search-index'; import type { FilterThreadInfo } from 'lib/types/filter-types'; -import type { AppState } from '../redux/redux-setup'; +import { useSelector } from '../redux/redux-utils'; -const webFilterThreadInfos: ( - state: AppState, -) => () => $ReadOnlyArray = createSelector( - filterThreadInfos, - (state: AppState) => state.navInfo.tab === 'calendar', - ( - threadInfoFunc: ( - calendarActive: boolean, - ) => $ReadOnlyArray, - calendarActive: boolean, - ) => () => threadInfoFunc(calendarActive), -); +function useFilterThreadInfos(): $ReadOnlyArray { + const calendarActive = useSelector(state => state.navInfo.tab === 'calendar'); + return baseUseFilterThreadInfos(calendarActive); +} -const webFilterThreadSearchIndex: ( - state: AppState, -) => () => SearchIndex = createSelector( - filterThreadSearchIndex, - (state: AppState) => state.navInfo.tab === 'calendar', - ( - threadSearchIndexFunc: (calendarActive: boolean) => SearchIndex, - calendarActive: boolean, - ) => () => threadSearchIndexFunc(calendarActive), -); +function useFilterThreadSearchIndex(): SearchIndex { + const calendarActive = useSelector(state => state.navInfo.tab === 'calendar'); + return baseUseFilterThreadSearchIndex(calendarActive); +} -export { webFilterThreadInfos, webFilterThreadSearchIndex }; +export { useFilterThreadInfos, useFilterThreadSearchIndex };