diff --git a/native/components/thread-list.react.js b/native/components/thread-list.react.js index 2dba67dc3..3f6de9aa2 100644 --- a/native/components/thread-list.react.js +++ b/native/components/thread-list.react.js @@ -1,154 +1,149 @@ // @flow import invariant from 'invariant'; import SearchIndex from 'lib/shared/search-index'; -import { type ThreadInfo, threadInfoPropType } from 'lib/types/thread-types'; -import { connect } from 'lib/utils/redux-utils'; -import PropTypes from 'prop-types'; +import type { ThreadInfo } from 'lib/types/thread-types'; import * as React from 'react'; -import { FlatList, ViewPropTypes, Text, TextInput } from 'react-native'; +import { FlatList, TextInput } from 'react-native'; import { createSelector } from 'reselect'; -import type { AppState } from '../redux/redux-setup'; import { - styleSelector, type IndicatorStyle, - indicatorStylePropType, - indicatorStyleSelector, + useStyles, + useIndicatorStyle, } from '../themes/colors'; import type { ViewStyle, TextStyle } from '../types/styles'; import { waitForModalInputFocus } from '../utils/timers'; import Search from './search.react'; import ThreadListThread from './thread-list-thread.react'; +type BaseProps = {| + +threadInfos: $ReadOnlyArray, + +onSelect: (threadID: string) => void, + +itemStyle?: ViewStyle, + +itemTextStyle?: TextStyle, + +searchIndex?: SearchIndex, +|}; type Props = {| - threadInfos: $ReadOnlyArray, - onSelect: (threadID: string) => void, - itemStyle?: ViewStyle, - itemTextStyle?: TextStyle, - searchIndex?: SearchIndex, + ...BaseProps, // Redux state - styles: typeof styles, - indicatorStyle: IndicatorStyle, + +styles: typeof unboundStyles, + +indicatorStyle: IndicatorStyle, |}; type State = {| - searchText: string, - searchResults: Set, + +searchText: string, + +searchResults: Set, |}; type PropsAndState = {| ...Props, ...State |}; class ThreadList extends React.PureComponent { - static propTypes = { - threadInfos: PropTypes.arrayOf(threadInfoPropType).isRequired, - onSelect: PropTypes.func.isRequired, - itemStyle: ViewPropTypes.style, - itemTextStyle: Text.propTypes.style, - searchIndex: PropTypes.instanceOf(SearchIndex), - styles: PropTypes.objectOf(PropTypes.object).isRequired, - indicatorStyle: indicatorStylePropType.isRequired, - }; state: State = { searchText: '', searchResults: new Set(), }; textInput: ?React.ElementRef; listDataSelector = createSelector( (propsAndState: PropsAndState) => propsAndState.threadInfos, (propsAndState: PropsAndState) => propsAndState.searchText, (propsAndState: PropsAndState) => propsAndState.searchResults, (propsAndState: PropsAndState) => propsAndState.itemStyle, (propsAndState: PropsAndState) => propsAndState.itemTextStyle, ( threadInfos: $ReadOnlyArray, text: string, searchResults: Set, ) => text ? threadInfos.filter((threadInfo) => searchResults.has(threadInfo.id)) : // We spread to make sure the result of this selector updates when // any input param (namely itemStyle or itemTextStyle) changes [...threadInfos], ); get listData() { return this.listDataSelector({ ...this.props, ...this.state }); } render() { let searchBar = null; if (this.props.searchIndex) { searchBar = ( ); } return ( {searchBar} ); } static keyExtractor(threadInfo: ThreadInfo) { return threadInfo.id; } renderItem = (row: { item: ThreadInfo }) => { return ( ); }; static getItemLayout(data: ?$ReadOnlyArray, index: number) { return { length: 24, offset: 24 * index, index }; } onChangeSearchText = (searchText: string) => { invariant(this.props.searchIndex, 'should be set'); const results = this.props.searchIndex.getSearchResults(searchText); this.setState({ searchText, searchResults: new Set(results) }); }; searchRef = async (textInput: ?React.ElementRef) => { this.textInput = textInput; if (!textInput) { return; } await waitForModalInputFocus(); if (this.textInput) { this.textInput.focus(); } }; } -const styles = { +const unboundStyles = { search: { marginBottom: 8, }, }; -const stylesSelector = styleSelector(styles); -export default connect((state: AppState) => ({ - styles: stylesSelector(state), - indicatorStyle: indicatorStyleSelector(state), -}))(ThreadList); +export default React.memo(function ConnectedThreadList( + props: BaseProps, +) { + const styles = useStyles(unboundStyles); + const indicatorStyle = useIndicatorStyle(); + + return ( + + ); +});