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<FilterThreadInfo> = 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<FilterThreadInfo> {
+  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<FilterThreadInfo>,
-  ) => (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<FilterThreadInfo>,
-  +filterThreadSearchIndex: () => SearchIndex,
+  +filterThreadInfos: $ReadOnlyArray<FilterThreadInfo>,
+  +filterThreadSearchIndex: SearchIndex,
   +filteredThreadIDs: ?$ReadOnlySet<string>,
   +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<HTMLInputElement>) => {
     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<FilterThreadInfo> = createSelector(
-  filterThreadInfos,
-  (state: AppState) => state.navInfo.tab === 'calendar',
-  (
-    threadInfoFunc: (
-      calendarActive: boolean,
-    ) => $ReadOnlyArray<FilterThreadInfo>,
-    calendarActive: boolean,
-  ) => () => threadInfoFunc(calendarActive),
-);
+function useFilterThreadInfos(): $ReadOnlyArray<FilterThreadInfo> {
+  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 };