UNPKG

react-vtree

Version:

React component for efficiently rendering large tree structures

144 lines (125 loc) 3.61 kB
/* eslint-disable react/no-unused-state,@typescript-eslint/consistent-type-assertions */ import React, { PureComponent } from 'react'; // eslint-disable-next-line @typescript-eslint/naming-convention,@typescript-eslint/prefer-readonly-parameter-types export const Row = ({ index, data: { component: Node, treeData, order, records }, style, isScrolling }) => /*#__PURE__*/React.createElement(Node, Object.assign({}, records[order[index]], { style: style, isScrolling: isScrolling, treeData: treeData })); export const createTreeComputer = ({ createRecord, shouldUpdateRecords, updateRecord, updateRecordOnNewData }) => ({ treeWalker }, state, options = {}) => { var _options$refreshNodes; const order = []; const records = { ...state.records }; const iter = treeWalker((_options$refreshNodes = options.refreshNodes) != null ? _options$refreshNodes : false); // Here we are updating all records to the provided openness state described // in UpdateOptions. It should be done before the tree re-calculation // because tree walker omits closed nodes while update is required for all // of them. if (shouldUpdateRecords(options)) { for (const id in records) { updateRecord(records[id], id, options); } } let isPreviousOpened = false; // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition,no-constant-condition while (true) { const { done, value } = iter.next(isPreviousOpened); if (done || !value) { break; } let id; if (typeof value === 'string' || typeof value === 'symbol') { id = value; } else { ({ id } = value); const record = records[id]; if (!record) { records[id] = createRecord(value, options, state); } else { record.data = value; updateRecordOnNewData(record, options); } } if (records[id]) { order.push(id); isPreviousOpened = records[id].isOpen; } else if (process.env.NODE_ENV === 'development') { // eslint-disable-next-line no-console console.error(`No record with id ${String(id)} found.`); } } return { order, records }; }; class Tree extends PureComponent { static getDerivedStateFromProps(props, state) { const { children: component, itemData: treeData, treeWalker } = props; const { computeTree, order, treeWalker: oldTreeWalker } = state; return { component, treeData, treeWalker, ...(treeWalker !== oldTreeWalker || !order ? computeTree(props, state, { refreshNodes: true }) : null) }; } constructor(props, context) { super(props, context); this.list = /*#__PURE__*/React.createRef(); this.state = { component: props.children, recomputeTree: this.recomputeTree.bind(this), records: {} }; } recomputeTree(options) { return new Promise(resolve => { this.setState(prevState => prevState.computeTree(this.props, prevState, options), resolve); }); } scrollTo(scrollOffset) { var _this$list$current; (_this$list$current = this.list.current) == null ? void 0 : _this$list$current.scrollTo(scrollOffset); } scrollToItem(id, align) { var _this$list$current2; // eslint-disable-next-line react/destructuring-assignment (_this$list$current2 = this.list.current) == null ? void 0 : _this$list$current2.scrollToItem(this.state.order.indexOf(id), align); } } Tree.defaultProps = { rowComponent: Row }; export default Tree;