Move search out of RoomList and LeftPanel, into RoomSearch

This prevents the entire left panel from having to re-mount whenever the search query changes.
pull/21833/head
Travis Ralston 2020-07-24 14:42:53 -06:00
parent 42498d32cc
commit c6033b9410
3 changed files with 20 additions and 40 deletions

View File

@ -44,7 +44,6 @@ interface IProps {
} }
interface IState { interface IState {
searchFilter: string;
showBreadcrumbs: boolean; showBreadcrumbs: boolean;
showTagPanel: boolean; showTagPanel: boolean;
} }
@ -69,7 +68,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
super(props); super(props);
this.state = { this.state = {
searchFilter: "",
showBreadcrumbs: BreadcrumbsStore.instance.visible, showBreadcrumbs: BreadcrumbsStore.instance.visible,
showTagPanel: SettingsStore.getValue('TagPanel.enableTagPanel'), showTagPanel: SettingsStore.getValue('TagPanel.enableTagPanel'),
}; };
@ -97,10 +95,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
this.props.resizeNotifier.off("middlePanelResizedNoisy", this.onResize); this.props.resizeNotifier.off("middlePanelResizedNoisy", this.onResize);
} }
private onSearch = (term: string): void => {
this.setState({searchFilter: term});
};
private onExplore = () => { private onExplore = () => {
dis.fire(Action.ViewRoomDirectory); dis.fire(Action.ViewRoomDirectory);
}; };
@ -366,7 +360,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
onKeyDown={this.onKeyDown} onKeyDown={this.onKeyDown}
> >
<RoomSearch <RoomSearch
onQueryUpdate={this.onSearch}
isMinimized={this.props.isMinimized} isMinimized={this.props.isMinimized}
onVerticalArrow={this.onKeyDown} onVerticalArrow={this.onKeyDown}
onEnter={this.onEnter} onEnter={this.onEnter}
@ -392,7 +385,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
onKeyDown={this.onKeyDown} onKeyDown={this.onKeyDown}
resizeNotifier={null} resizeNotifier={null}
collapsed={false} collapsed={false}
searchFilter={this.state.searchFilter}
onFocus={this.onFocus} onFocus={this.onFocus}
onBlur={this.onBlur} onBlur={this.onBlur}
isMinimized={this.props.isMinimized} isMinimized={this.props.isMinimized}

View File

@ -24,9 +24,10 @@ import { throttle } from 'lodash';
import { Key } from "../../Keyboard"; import { Key } from "../../Keyboard";
import AccessibleButton from "../views/elements/AccessibleButton"; import AccessibleButton from "../views/elements/AccessibleButton";
import { Action } from "../../dispatcher/actions"; import { Action } from "../../dispatcher/actions";
import RoomListStore from "../../stores/room-list/RoomListStore";
import { NameFilterCondition } from "../../stores/room-list/filters/NameFilterCondition";
interface IProps { interface IProps {
onQueryUpdate: (newQuery: string) => void;
isMinimized: boolean; isMinimized: boolean;
onVerticalArrow(ev: React.KeyboardEvent): void; onVerticalArrow(ev: React.KeyboardEvent): void;
onEnter(ev: React.KeyboardEvent): boolean; onEnter(ev: React.KeyboardEvent): boolean;
@ -40,6 +41,7 @@ interface IState {
export default class RoomSearch extends React.PureComponent<IProps, IState> { export default class RoomSearch extends React.PureComponent<IProps, IState> {
private dispatcherRef: string; private dispatcherRef: string;
private inputRef: React.RefObject<HTMLInputElement> = createRef(); private inputRef: React.RefObject<HTMLInputElement> = createRef();
private searchFilter: NameFilterCondition = new NameFilterCondition();
constructor(props: IProps) { constructor(props: IProps) {
super(props); super(props);
@ -52,6 +54,21 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
this.dispatcherRef = defaultDispatcher.register(this.onAction); this.dispatcherRef = defaultDispatcher.register(this.onAction);
} }
public componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>): void {
if (prevState.query !== this.state.query) {
const hadSearch = !!this.searchFilter.search.trim();
const haveSearch = !!this.state.query.trim();
this.searchFilter.search = this.state.query;
if (!hadSearch && haveSearch) {
// started a new filter - add the condition
RoomListStore.instance.addFilter(this.searchFilter);
} else if (hadSearch && !haveSearch) {
// cleared a filter - remove the condition
RoomListStore.instance.removeFilter(this.searchFilter);
} // else the filter hasn't changed enough for us to care here
}
}
public componentWillUnmount() { public componentWillUnmount() {
defaultDispatcher.unregister(this.dispatcherRef); defaultDispatcher.unregister(this.dispatcherRef);
} }
@ -78,19 +95,8 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
private onChange = () => { private onChange = () => {
if (!this.inputRef.current) return; if (!this.inputRef.current) return;
this.setState({query: this.inputRef.current.value}); this.setState({query: this.inputRef.current.value});
this.onSearchUpdated();
}; };
// it wants this at the top of the file, but we know better
// tslint:disable-next-line
private onSearchUpdated = throttle(
() => {
// We can't use the state variable because it can lag behind the input.
// The lag is most obvious when deleting/clearing text with the keyboard.
this.props.onQueryUpdate(this.inputRef.current.value);
}, 200, {trailing: true, leading: true},
);
private onFocus = (ev: React.FocusEvent<HTMLInputElement>) => { private onFocus = (ev: React.FocusEvent<HTMLInputElement>) => {
this.setState({focused: true}); this.setState({focused: true});
ev.target.select(); ev.target.select();

View File

@ -31,7 +31,6 @@ import dis from "../../../dispatcher/dispatcher";
import defaultDispatcher from "../../../dispatcher/dispatcher"; import defaultDispatcher from "../../../dispatcher/dispatcher";
import RoomSublist from "./RoomSublist"; import RoomSublist from "./RoomSublist";
import { ActionPayload } from "../../../dispatcher/payloads"; import { ActionPayload } from "../../../dispatcher/payloads";
import { NameFilterCondition } from "../../../stores/room-list/filters/NameFilterCondition";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import GroupAvatar from "../avatars/GroupAvatar"; import GroupAvatar from "../avatars/GroupAvatar";
import TemporaryTile from "./TemporaryTile"; import TemporaryTile from "./TemporaryTile";
@ -52,7 +51,6 @@ interface IProps {
onResize: () => void; onResize: () => void;
resizeNotifier: ResizeNotifier; resizeNotifier: ResizeNotifier;
collapsed: boolean; collapsed: boolean;
searchFilter: string;
isMinimized: boolean; isMinimized: boolean;
} }
@ -150,8 +148,7 @@ function customTagAesthetics(tagId: TagID): ITagAesthetics {
}; };
} }
export default class RoomList extends React.Component<IProps, IState> { export default class RoomList extends React.PureComponent<IProps, IState> {
private searchFilter: NameFilterCondition = new NameFilterCondition();
private dispatcherRef; private dispatcherRef;
private customTagStoreRef; private customTagStoreRef;
@ -165,21 +162,6 @@ export default class RoomList extends React.Component<IProps, IState> {
this.dispatcherRef = defaultDispatcher.register(this.onAction); this.dispatcherRef = defaultDispatcher.register(this.onAction);
} }
public componentDidUpdate(prevProps: Readonly<IProps>): void {
if (prevProps.searchFilter !== this.props.searchFilter) {
const hadSearch = !!this.searchFilter.search.trim();
const haveSearch = !!this.props.searchFilter.trim();
this.searchFilter.search = this.props.searchFilter;
if (!hadSearch && haveSearch) {
// started a new filter - add the condition
RoomListStore.instance.addFilter(this.searchFilter);
} else if (hadSearch && !haveSearch) {
// cleared a filter - remove the condition
RoomListStore.instance.removeFilter(this.searchFilter);
} // else the filter hasn't changed enough for us to care here
}
}
public componentDidMount(): void { public componentDidMount(): void {
RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.updateLists); RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.updateLists);
this.customTagStoreRef = CustomRoomTagStore.addListener(this.updateLists); this.customTagStoreRef = CustomRoomTagStore.addListener(this.updateLists);
@ -339,7 +321,7 @@ export default class RoomList extends React.Component<IProps, IState> {
isMinimized={this.props.isMinimized} isMinimized={this.props.isMinimized}
onResize={this.props.onResize} onResize={this.props.onResize}
extraBadTilesThatShouldntExist={extraTiles} extraBadTilesThatShouldntExist={extraTiles}
isFiltered={!!this.searchFilter.search} isFiltered={!!RoomListStore.instance.getFirstNameFilterCondition()}
/> />
); );
} }