immutable data structures in tables 3/n: searchable table
Summary: Migrating tables' row collection to Immutable.js List: 1. Сopy SearchableTable code to SearchableTable_immutable 2. Use ManagedTable_immutable for SearchableTable_immutable ----- Current implementation of tables forces to copy arrays on new data arrival which causes O(N^2) complexity -> tables can't handle a lot of new rows in short period of time -> tables freeze and become unresponsive for a few seconds. Immutable data structures will bring us to O(N) complexity Reviewed By: jknoxville Differential Revision: D16416732 fbshipit-source-id: 856ba0407bfdd12bb1b90110e130562a07cc5060
This commit is contained in:
committed by
Facebook Github Bot
parent
6deaf2106f
commit
d3658f7d31
146
src/ui/components/searchable/SearchableTable_immutable.js
Normal file
146
src/ui/components/searchable/SearchableTable_immutable.js
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2018-present Facebook.
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type {ManagedTableProps_immutable, TableBodyRow, Filter} from 'flipper';
|
||||||
|
import type {SearchableProps} from './Searchable.js';
|
||||||
|
import {PureComponent} from 'react';
|
||||||
|
import ManagedTable_immutable from '../table/ManagedTable_immutable.js';
|
||||||
|
|
||||||
|
import textContent from '../../../utils/textContent.js';
|
||||||
|
import Searchable from './Searchable.js';
|
||||||
|
import deepEqual from 'deep-equal';
|
||||||
|
|
||||||
|
type Props = {|
|
||||||
|
...ManagedTableProps_immutable,
|
||||||
|
...SearchableProps,
|
||||||
|
/** Reference to the table */
|
||||||
|
innerRef?: (ref: React.ElementRef<*>) => void,
|
||||||
|
/** Filters that are added to the filterbar by default */
|
||||||
|
defaultFilters: Array<Filter>,
|
||||||
|
|};
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
filterRows: (row: TableBodyRow) => boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
const rowMatchesFilters = (filters: Array<Filter>, row: TableBodyRow) =>
|
||||||
|
filters
|
||||||
|
.map((filter: Filter) => {
|
||||||
|
if (filter.type === 'enum' && row.type != null) {
|
||||||
|
return filter.value.length === 0 || filter.value.indexOf(row.type) > -1;
|
||||||
|
} else if (filter.type === 'include') {
|
||||||
|
return (
|
||||||
|
textContent(row.columns[filter.key].value).toLowerCase() ===
|
||||||
|
filter.value.toLowerCase()
|
||||||
|
);
|
||||||
|
} else if (filter.type === 'exclude') {
|
||||||
|
return (
|
||||||
|
textContent(row.columns[filter.key].value).toLowerCase() !==
|
||||||
|
filter.value.toLowerCase()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.every(x => x === true);
|
||||||
|
|
||||||
|
function rowMatchesRegex(values: Array<string>, regex: string): boolean {
|
||||||
|
try {
|
||||||
|
const re = new RegExp(regex);
|
||||||
|
return values.some(x => re.test(x));
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function rowMatchesSearchTerm(
|
||||||
|
searchTerm: string,
|
||||||
|
isRegex: boolean,
|
||||||
|
row: TableBodyRow,
|
||||||
|
): boolean {
|
||||||
|
if (searchTerm == null || searchTerm.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const rowValues = Object.keys(row.columns).map(key =>
|
||||||
|
textContent(row.columns[key].value),
|
||||||
|
);
|
||||||
|
if (isRegex) {
|
||||||
|
return rowMatchesRegex(rowValues, searchTerm);
|
||||||
|
}
|
||||||
|
return rowValues.some(x =>
|
||||||
|
x.toLowerCase().includes(searchTerm.toLowerCase()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterRowsFactory = (
|
||||||
|
filters: Array<Filter>,
|
||||||
|
searchTerm: string,
|
||||||
|
regexSearch: boolean,
|
||||||
|
) => (row: TableBodyRow): boolean =>
|
||||||
|
rowMatchesFilters(filters, row) &&
|
||||||
|
rowMatchesSearchTerm(searchTerm, regexSearch, row);
|
||||||
|
|
||||||
|
class SearchableManagedTable_immutable extends PureComponent<Props, State> {
|
||||||
|
static defaultProps = {
|
||||||
|
defaultFilters: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
filterRows: filterRowsFactory(
|
||||||
|
this.props.filters,
|
||||||
|
this.props.searchTerm,
|
||||||
|
this.props.regexEnabled || false,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.defaultFilters.map(this.props.addFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps: Props) {
|
||||||
|
if (
|
||||||
|
nextProps.searchTerm !== this.props.searchTerm ||
|
||||||
|
nextProps.regexEnabled != this.props.regexEnabled ||
|
||||||
|
!deepEqual(this.props.filters, nextProps.filters)
|
||||||
|
) {
|
||||||
|
this.setState({
|
||||||
|
filterRows: filterRowsFactory(
|
||||||
|
nextProps.filters,
|
||||||
|
nextProps.searchTerm,
|
||||||
|
nextProps.regexEnabled || false,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
addFilter,
|
||||||
|
searchTerm: _searchTerm,
|
||||||
|
filters: _filters,
|
||||||
|
innerRef,
|
||||||
|
rows,
|
||||||
|
...props
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ManagedTable_immutable
|
||||||
|
{...props}
|
||||||
|
filter={this.state.filterRows}
|
||||||
|
rows={rows.filter(this.state.filterRows)}
|
||||||
|
onAddFilter={addFilter}
|
||||||
|
ref={innerRef}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table with filter and searchbar, supports all properties a ManagedTable
|
||||||
|
* and Searchable supports.
|
||||||
|
*/
|
||||||
|
export default Searchable(SearchableManagedTable_immutable);
|
||||||
@@ -158,6 +158,9 @@ export {
|
|||||||
export {
|
export {
|
||||||
default as SearchableTable,
|
default as SearchableTable,
|
||||||
} from './components/searchable/SearchableTable.js';
|
} from './components/searchable/SearchableTable.js';
|
||||||
|
export {
|
||||||
|
default as SearchableTable_immutable,
|
||||||
|
} from './components/searchable/SearchableTable_immutable.js';
|
||||||
export type {SearchableProps} from './components/searchable/Searchable.js';
|
export type {SearchableProps} from './components/searchable/Searchable.js';
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user