fix cell level performace, remain select all

This commit is contained in:
AllenFang 2018-09-01 12:56:57 +08:00
parent c3996f3f47
commit dffe588f66
12 changed files with 165 additions and 131 deletions

View File

@ -1,5 +1,4 @@
import createContext from './src/context';
import bindCellLevelCellEdit from './src/cell-binder';
import bindRowLevelCellEdit from './src/row-binder';
import createEditingCell from './src/editing-cell-binder';
import {
@ -11,7 +10,6 @@ import {
export default (options = {}) => ({
createContext,
createEditingCell,
bindCellLevelCellEdit,
bindRowLevelCellEdit,
DBCLICK_TO_CELL_EDIT,
DELAY_FOR_DBCLICK,

View File

@ -1,38 +0,0 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import { CLICK_TO_CELL_EDIT, DBCLICK_TO_CELL_EDIT } from './const';
import { Consumer } from './context';
export default (Component, keyField, _) => {
const renderWithCellEdit = (props, cellEdit) => {
const content = _.get(props.row, props.column.dataField);
const editableRow = props.editable;
let editable = _.isDefined(props.column.editable) ? props.column.editable : true;
if (props.column.dataField === keyField || !editableRow) editable = false;
if (_.isFunction(props.column.editable)) {
editable = props.column.editable(
content,
props.row,
props.rowIndex,
props.columnIndex
);
}
return (
<Component
{ ...props }
onStart={ cellEdit.onStart }
editable={ editable }
clickToEdit={ cellEdit.mode === CLICK_TO_CELL_EDIT }
dbclickToEdit={ cellEdit.mode === DBCLICK_TO_CELL_EDIT }
/>
);
};
return props => (
<Consumer>
{ cellEdit => renderWithCellEdit(props, cellEdit) }
</Consumer>
);
};

View File

@ -100,7 +100,6 @@ export default (
const {
cellEdit: {
options: { nonEditableRows, errorMessage, ...optionsRest },
createContext,
...cellEditRest
}
} = this.props;

View File

@ -4,6 +4,7 @@ import { Consumer } from './context';
import createEditingCell from './editing-cell';
export default (_) => {
const EditingCell = createEditingCell(_);
const renderWithEditingCell = (props, cellEdit) => {
const content = _.get(props.row, props.column.dataField);
let editCellstyle = props.column.editCellStyle || {};
@ -24,7 +25,7 @@ export default (_) => {
props.columnIndex)
;
}
const EditingCell = createEditingCell(_);
return (
<EditingCell
{ ...props }

View File

@ -1,6 +1,6 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import { DELAY_FOR_DBCLICK, DBCLICK_TO_CELL_EDIT } from './const';
import { DELAY_FOR_DBCLICK, DBCLICK_TO_CELL_EDIT, CLICK_TO_CELL_EDIT } from './const';
import { Consumer } from './context';
export default (Component, selectRowEnabled) => {
@ -24,6 +24,9 @@ export default (Component, selectRowEnabled) => {
editingRowIdx={ cellEdit.ridx }
editingColIdx={ cellEdit.cidx }
editable={ editableRow }
onStart={ cellEdit.onStart }
clickToEdit={ cellEdit.mode === CLICK_TO_CELL_EDIT }
dbclickToEdit={ cellEdit.mode === DBCLICK_TO_CELL_EDIT }
/>
);
};

View File

@ -4,7 +4,7 @@ import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory from 'react-bootstrap-table2-editor';
import { productsGenerator } from 'utils/common';
const products = productsGenerator(5000);
const products = productsGenerator(5);
const columns = [{
dataField: 'id',
@ -23,7 +23,6 @@ export default () => (
keyField="id"
data={ products }
columns={ columns }
selectRow={ { mode: 'checkbox' } }
cellEdit={ cellEditFactory({
mode: 'click'
}) }

View File

@ -6,89 +6,94 @@ import PropTypes from 'prop-types';
import _ from './utils';
import Row from './row';
import Cell from './cell';
import RowAggregator from './row-aggregator';
import RowSection from './row-section';
import Const from './const';
import bindSelection from './row-selection/row-binder';
import bindExpansion from './row-expand/row-binder';
const Body = (props) => {
const {
columns,
data,
keyField,
isEmpty,
noDataIndication,
visibleColumnSize,
cellEdit,
selectRow,
rowStyle,
rowClasses,
rowEvents,
expandRow
} = props;
let content;
if (isEmpty) {
const indication = _.isFunction(noDataIndication) ? noDataIndication() : noDataIndication;
if (!indication) {
return null;
class Body extends React.Component {
constructor(props) {
super(props);
if (props.cellEdit.createContext) {
this.EditingCell = props.cellEdit.createEditingCell(_, props.cellEdit.options.onStartEdit);
}
content = <RowSection content={ indication } colSpan={ visibleColumnSize } />;
} else {
let RowComponent = Row;
const selectRowEnabled = selectRow.mode !== Const.ROW_SELECT_DISABLED;
const expandRowEnabled = !!expandRow.renderer;
const additionalRowProps = {};
if (expandRowEnabled) {
RowComponent = bindExpansion(RowAggregator, visibleColumnSize);
}
if (selectRowEnabled) {
RowComponent = bindSelection(expandRowEnabled ? RowComponent : RowAggregator);
}
if (cellEdit.createContext) {
const CellComponent = cellEdit.bindCellLevelCellEdit(Cell, keyField, _);
const EditingCell = cellEdit.createEditingCell(_, cellEdit.options.onStartEdit);
RowComponent = cellEdit.bindRowLevelCellEdit(RowComponent, selectRowEnabled);
additionalRowProps.CellComponent = CellComponent;
additionalRowProps.EditingCellComponent = EditingCell;
}
if (selectRowEnabled || expandRowEnabled) {
additionalRowProps.expandRow = expandRow;
additionalRowProps.selectRow = selectRow;
}
content = data.map((row, index) => {
const key = _.get(row, keyField);
const baseRowProps = {
key,
row,
columns,
keyField,
cellEdit,
value: key,
rowIndex: index,
attrs: rowEvents || {},
...additionalRowProps
};
baseRowProps.style = _.isFunction(rowStyle) ? rowStyle(row, index) : rowStyle;
baseRowProps.className = (_.isFunction(rowClasses) ? rowClasses(row, index) : rowClasses);
return <RowComponent { ...baseRowProps } />;
});
}
return (
<tbody>{ content }</tbody>
);
};
render() {
const {
columns,
data,
keyField,
isEmpty,
noDataIndication,
visibleColumnSize,
cellEdit,
selectRow,
rowStyle,
rowClasses,
rowEvents,
expandRow
} = this.props;
let content;
if (isEmpty) {
const indication = _.isFunction(noDataIndication) ? noDataIndication() : noDataIndication;
if (!indication) {
return null;
}
content = <RowSection content={ indication } colSpan={ visibleColumnSize } />;
} else {
let RowComponent = Row;
const selectRowEnabled = selectRow.mode !== Const.ROW_SELECT_DISABLED;
const expandRowEnabled = !!expandRow.renderer;
const additionalRowProps = {};
if (expandRowEnabled) {
RowComponent = bindExpansion(RowAggregator, visibleColumnSize);
}
if (selectRowEnabled) {
RowComponent = bindSelection(expandRowEnabled ? RowComponent : RowAggregator);
}
if (cellEdit.createContext) {
RowComponent = cellEdit.bindRowLevelCellEdit(RowComponent, selectRowEnabled, keyField, _);
additionalRowProps.EditingCellComponent = this.EditingCell;
}
if (selectRowEnabled || expandRowEnabled) {
additionalRowProps.expandRow = expandRow;
additionalRowProps.selectRow = selectRow;
}
content = data.map((row, index) => {
const key = _.get(row, keyField);
const baseRowProps = {
key,
row,
columns,
keyField,
cellEdit,
value: key,
rowIndex: index,
attrs: rowEvents || {},
...additionalRowProps
};
baseRowProps.style = _.isFunction(rowStyle) ? rowStyle(row, index) : rowStyle;
baseRowProps.className = (_.isFunction(rowClasses) ? rowClasses(row, index) : rowClasses);
return <RowComponent { ...baseRowProps } />;
});
}
return (
<tbody>{ content }</tbody>
);
}
}
Body.propTypes = {
keyField: PropTypes.string.isRequired,

View File

@ -6,8 +6,9 @@ import _ from './utils';
import Row from './row';
import ExpandCell from './row-expand/expand-cell';
import SelectionCell from './row-selection/selection-cell';
import shouldRowUpdater from './row-should-updater';
export default class RowAggregator extends React.Component {
export default class RowAggregator extends shouldRowUpdater(React.Component) {
static propTypes = {
attrs: PropTypes.object
}
@ -21,6 +22,17 @@ export default class RowAggregator extends React.Component {
this.createClickEventHandler = this.createClickEventHandler.bind(this);
}
shouldComponentUpdate(nextProps) {
const shouldUpdate =
this.props.selected !== nextProps.selected ||
this.props.expanded !== nextProps.expanded ||
this.props.selectable !== nextProps.selectable ||
this.shouldUpdateByWhenEditing(nextProps) ||
this.shouldUpdatedByNormalProps(nextProps);
return shouldUpdate;
}
createClickEventHandler(cb) {
return (e) => {
const {
@ -91,6 +103,7 @@ export default class RowAggregator extends React.Component {
return (
<Row
shouldUpdate
key={ key }
row={ row }
keyField={ keyField }

View File

@ -28,7 +28,7 @@ export default (Component) => {
...style,
...selectedStyle
};
className = cs(className, selectedClasses);
className = cs(className, selectedClasses) || undefined;
if (selectRow.bgColor) {
style = style || {};

View File

@ -25,9 +25,13 @@ export default class SelectionCell extends Component {
}
shouldComponentUpdate(nextProps) {
const { selected } = this.props;
const shouldUpdate =
this.props.rowIndex !== nextProps.rowIndex ||
this.props.selected !== nextProps.selected ||
this.props.disabled !== nextProps.disabled ||
this.props.rowKey !== nextProps.rowKey;
return nextProps.selected !== selected;
return shouldUpdate;
}
handleClick(e) {

View File

@ -0,0 +1,25 @@
/* eslint react/prop-types: 0 */
import _ from './utils';
export default ExtendBase =>
class RowShouldUpdater extends ExtendBase {
shouldUpdateByWhenEditing(nextProps) {
return (
nextProps.editingRowIdx === nextProps.rowIndex ||
(this.props.editingRowIdx === nextProps.rowIndex &&
nextProps.editingRowIdx === null)
);
}
shouldUpdatedByNormalProps(nextProps) {
const shouldUpdate =
this.props.rowIndex !== nextProps.rowIndex ||
this.props.className !== nextProps.className ||
this.props.editable !== nextProps.editable ||
this.props.columns.length !== nextProps.columns.length ||
!_.isEqual(this.props.row, nextProps.row) ||
!_.isEqual(this.props.style, nextProps.style);
return shouldUpdate;
}
};

View File

@ -6,11 +6,23 @@ import PropTypes from 'prop-types';
import _ from './utils';
import Cell from './cell';
import eventDelegater from './row-event-delegater';
import shouldRowUpdater from './row-should-updater';
class Row extends shouldRowUpdater(eventDelegater(Component)) {
shouldComponentUpdate(nextProps) {
console.log('lol');
const shouldUpdate =
nextProps.shouldUpdate ||
this.shouldUpdateByWhenEditing(nextProps) ||
this.shouldUpdatedByNormalProps(nextProps);
return shouldUpdate;
}
class Row extends eventDelegater(Component) {
render() {
const {
row,
keyField,
columns,
rowIndex,
className,
@ -18,9 +30,11 @@ class Row extends eventDelegater(Component) {
attrs,
editable,
editingRowIdx,
editingColIdx
editingColIdx,
onStart,
clickToEdit,
dbclickToEdit
} = this.props;
const CellComponent = this.props.CellComponent || Cell;
const trAttrs = this.delegate(attrs);
return (
@ -35,7 +49,7 @@ class Row extends eventDelegater(Component) {
const EditingCell = this.props.EditingCellComponent;
return (
<EditingCell
key={ `${content}-${index}` }
key={ `${content}-${index}-editing` }
row={ row }
rowIndex={ rowIndex }
column={ column }
@ -82,14 +96,23 @@ class Row extends eventDelegater(Component) {
if (cellClasses) cellAttrs.className = cellClasses;
if (!_.isEmptyObject(cellStyle)) cellAttrs.style = cellStyle;
let editableCell = _.isDefined(column.editable) ? column.editable : true;
if (column.dataField === keyField || !editable) editableCell = false;
if (_.isFunction(column.editable)) {
editableCell = column.editable(content, row, rowIndex, index);
}
return (
<CellComponent
<Cell
key={ `${content}-${index}` }
row={ row }
editable={ editable }
editable={ editableCell }
rowIndex={ rowIndex }
columnIndex={ index }
column={ column }
onStart={ onStart }
clickToEdit={ clickToEdit }
dbclickToEdit={ dbclickToEdit }
{ ...cellAttrs }
/>
);
@ -108,14 +131,16 @@ Row.propTypes = {
columns: PropTypes.array.isRequired,
style: PropTypes.object,
className: PropTypes.string,
attrs: PropTypes.object
attrs: PropTypes.object,
shouldUpdate: PropTypes.bool
};
Row.defaultProps = {
editable: true,
style: {},
className: null,
attrs: {}
attrs: {},
shouldUpdate: false
};
export default Row;