react-vtree
Version:
React component for efficiently rendering large tree structures
104 lines (90 loc) • 2.86 kB
JavaScript
import React from 'react';
import { VariableSizeList } from 'react-window';
import Tree, { createTreeComputer } from './Tree';
import { shouldUpdateRecords, updateRecord, updateRecordOnNewData } from './utils';
const computeTree = createTreeComputer({
createRecord: (data, {
opennessState
}, {
recomputeTree,
resetAfterId
}) => {
var _opennessState;
const record = {
data,
height: data.defaultHeight,
isOpen: (_opennessState = opennessState == null ? void 0 : opennessState[data.id]) != null ? _opennessState : data.isOpenByDefault,
resize(height, shouldForceUpdate) {
record.height = height;
resetAfterId(record.data.id, shouldForceUpdate);
},
toggle() {
record.isOpen = !record.isOpen;
return recomputeTree({
refreshNodes: record.isOpen,
useDefaultHeight: true
});
}
};
return record;
},
shouldUpdateRecords: options => {
var _options$useDefaultHe;
return shouldUpdateRecords(options) || ((_options$useDefaultHe = options.useDefaultHeight) != null ? _options$useDefaultHe : false);
},
updateRecord: (record, recordId, options) => {
if (options.useDefaultHeight) {
record.height = record.data.defaultHeight;
}
updateRecord(record, recordId, options);
},
updateRecordOnNewData: (record, options) => {
updateRecordOnNewData(record, options);
if (options.useDefaultHeight) {
record.height = record.data.defaultHeight;
}
}
});
export class VariableSizeTree extends Tree {
constructor(props, context) {
super(props, context);
this.getItemSize = this.getItemSize.bind(this);
this.state = { ...this.state,
computeTree,
resetAfterId: this.resetAfterId.bind(this)
};
}
resetAfterId(id, shouldForceUpdate = false) {
var _this$list$current;
(_this$list$current = this.list.current) == null ? void 0 : _this$list$current.resetAfterIndex(this.state.order.indexOf(id), shouldForceUpdate);
}
recomputeTree(options) {
return super.recomputeTree(options).then(() => {
var _this$list$current2;
(_this$list$current2 = this.list.current) == null ? void 0 : _this$list$current2.resetAfterIndex(0, true);
});
}
render() {
const {
children,
itemSize,
rowComponent,
treeWalker,
...rest
} = this.props;
return /*#__PURE__*/React.createElement(VariableSizeList, Object.assign({}, rest, {
itemCount: this.state.order.length,
itemData: this.state // eslint-disable-next-line @typescript-eslint/unbound-method
,
itemSize: itemSize != null ? itemSize : this.getItemSize,
ref: this.list
}), rowComponent);
}
getItemSize(index) {
const {
order,
records
} = this.state;
return records[order[index]].height;
}
}