Skip to content

Commit

Permalink
improve performance
Browse files Browse the repository at this point in the history
  • Loading branch information
warmhug committed Apr 3, 2016
1 parent 4e7c4d7 commit 939e7fc
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 124 deletions.
4 changes: 4 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# History
---

## 1.2.0 / 2016-04-03
- improve performance.
- add `checkStrictly` api.

## 1.1.0 / 2016-01-25
- change `onDrop` params (from `originExpandedKeys` to `rawExpandedKeys`)

Expand Down
1 change: 1 addition & 0 deletions examples/basic-controlled.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const Demo = React.createClass({
getInitialState() {
return {
expandedKeys: getFilterExpandedKeys(gData, ['0-0-0-key']),
// checkedKeys: ['0-0-0-0-key', '0-0-1-0-key', '0-1-0-0-key'],
checkedKeys: ['0-0-0-key'],
selectedKeys: [],
};
Expand Down
53 changes: 29 additions & 24 deletions examples/util.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

/* eslint no-loop-func: 0*/
const x = 3;
const y = 2;
const z = 1;
Expand Down Expand Up @@ -40,34 +40,39 @@ export function isInclude(smallArray, bigArray) {
}
// console.log(isInclude(['0', '1'], ['0', '10', '1']));

function uniqueArray(arr) {
const obj = {};
arr.forEach(item => {
if (!obj[item]) {
obj[item] = true;
}
});
return Object.keys(obj);
}
// console.log(uniqueArray(['11', '2', '2']));

// arr.length === 628, use time: ~20ms
export function filterParentPosition(arr) {
const a = [].concat(arr);
const levelObj = {};
arr.forEach((item) => {
const itemArr = item.split('-');
a.forEach((ii, index) => {
const iiArr = ii.split('-');
if (itemArr.length <= iiArr.length && isInclude(itemArr, iiArr)) {
a[index] = item;
}
if (itemArr.length > iiArr.length && isInclude(iiArr, itemArr)) {
a[index] = ii;
}
});
const posLen = item.split('-').length;
if (!levelObj[posLen]) {
levelObj[posLen] = [];
}
levelObj[posLen].push(item);
});
const levelArr = Object.keys(levelObj).sort();
for (let i = 0; i < levelArr.length; i++) {
if (levelArr[i + 1]) {
levelObj[levelArr[i]].forEach(ii => {
for (let j = i + 1; j < levelArr.length; j++) {
levelObj[levelArr[j]].forEach((_i, index) => {
if (isInclude(ii.split('-'), _i.split('-'))) {
levelObj[levelArr[j]][index] = null;
}
});
levelObj[levelArr[j]] = levelObj[levelArr[j]].filter(p => p);
}
});
}
}
let nArr = [];
levelArr.forEach(i => {
nArr = nArr.concat(levelObj[i]);
});
return uniqueArray(a);
return nArr;
}
// console.log(filterParentPosition(['0-2', '0-10', '0-0-1', '0-1-1', '0-0','0-1', '0-10-0']));
// console.log(filterParentPosition(['0-2', '0-3-3', '0-10', '0-10-0', '0-0-1', '0-0', '0-1-1', '0-1']));


function loopData(data, callback) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rc-tree",
"version": "1.2.0-beta.1",
"version": "1.2.0-beta.2",
"description": "tree ui component for react",
"keywords": [
"react",
Expand Down
95 changes: 79 additions & 16 deletions src/Tree.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import React, {PropTypes} from 'react';
import assign from 'object-assign';
import classNames from 'classnames';
import { loopAllChildren, isInclude, getOffset, getTreeNodesStates } from './util';
import {
loopAllChildren, isInclude, getOffset,
filterParentPosition, handleCheckState, getCheckKeys,
} from './util';

function noop() {
}
Expand All @@ -13,6 +16,7 @@ class Tree extends React.Component {
this[m] = this[m].bind(this);
});
this.contextmenuKeys = [];
this.checkedKeysChange = true;

this.state = {
expandedKeys: this.getDefaultExpandedKeys(props),
Expand All @@ -33,6 +37,11 @@ class Tree extends React.Component {
st.expandedKeys = expandedKeys;
}
if (checkedKeys) {
if (checkedKeys === this.props.checkedKeys) {
this.checkedKeysChange = false;
} else {
this.checkedKeysChange = true;
}
st.checkedKeys = checkedKeys;
}
if (selectedKeys) {
Expand Down Expand Up @@ -179,9 +188,6 @@ class Tree extends React.Component {
const key = treeNode.key || treeNode.props.eventKey;
let checkedKeys = [...this.state.checkedKeys];
const index = checkedKeys.indexOf(key);
if (checked && index === -1) {
checkedKeys.push(key);
}

const newSt = {
event: 'check',
Expand All @@ -191,22 +197,40 @@ class Tree extends React.Component {

// checkStrictly
if (this.props.checkStrictly && ('checkedKeys' in this.props)) {
if (checked && index === -1) {
checkedKeys.push(key);
}
if (!checked && index > -1) {
checkedKeys.splice(index, 1);
}
newSt.checkedNodes = [];
loopAllChildren(this.props.children, (item, ind, pos, keyOrPos) => {
if (checkedKeys.indexOf(keyOrPos) !== -1) {
checked = true;
newSt.checkedNodes.push(item);
}
});
} else {
const checkKeys = getTreeNodesStates(this.props.children, checkedKeys, checked, key);
if (checked && index === -1) {
this.treeNodesStates[treeNode.props.pos].checked = true;
const checkedPositions = [];
Object.keys(this.treeNodesStates).forEach(i => {
if (this.treeNodesStates[i].checked) {
checkedPositions.push(i);
}
});
handleCheckState(this.treeNodesStates, filterParentPosition(checkedPositions), true);
}
if (!checked) {
this.treeNodesStates[treeNode.props.pos].checked = false;
this.treeNodesStates[treeNode.props.pos].checkPart = false;
handleCheckState(this.treeNodesStates, [treeNode.props.pos], false);
}
const checkKeys = getCheckKeys(this.treeNodesStates);
newSt.checkedNodes = checkKeys.checkedNodes;
newSt.checkedNodesPositions = checkKeys.checkedNodesPositions;
this.checkKeys = checkKeys;

checkedKeys = checkKeys.checkedKeys;
this._checkedKeys = checkedKeys = checkKeys.checkedKeys;
if (!('checkedKeys' in this.props)) {
this.setState({
checkedKeys,
Expand Down Expand Up @@ -417,21 +441,25 @@ class Tree extends React.Component {
prefixCls: props.prefixCls,
showLine: props.showLine,
showIcon: props.showIcon,
checkable: props.checkable,
draggable: props.draggable,
dragOver: state.dragOverNodeKey === key && this.dropPosition === 0,
dragOverGapTop: state.dragOverNodeKey === key && this.dropPosition === -1,
dragOverGapBottom: state.dragOverNodeKey === key && this.dropPosition === 1,
expanded: state.expandedKeys.indexOf(key) !== -1,
selected: state.selectedKeys.indexOf(key) !== -1,
checked: (props.checkStrictly ? state.checkedKeys : this.checkedKeys).indexOf(key) !== -1,
checkPart: props.checkStrictly ? false : this.checkPartKeys.indexOf(key) !== -1,
openTransitionName: this.getOpenTransitionName(),
openAnimation: props.openAnimation,
filterTreeNode: this.filterTreeNode.bind(this),
};
if (this.treeNodesStates[pos]) {
assign(cloneProps, this.treeNodesStates[pos].siblingPosition);
if (props.checkable) {
cloneProps.checkable = props.checkable;
cloneProps.checked = (props.checkStrictly ? state.checkedKeys : this.checkedKeys).
indexOf(key) !== -1;
cloneProps.checkPart = props.checkStrictly ? false : this.checkPartKeys.
indexOf(key) !== -1;
if (this.treeNodesStates[pos]) {
assign(cloneProps, this.treeNodesStates[pos].siblingPosition);
}
}
return React.cloneElement(child, cloneProps);
}
Expand All @@ -447,10 +475,45 @@ class Tree extends React.Component {
domProps.onKeyDown = this.onKeyDown;
}
// console.log(this.state.expandedKeys, this._rawExpandedKeys, props.children);
const checkKeys = getTreeNodesStates(props.children, this.state.checkedKeys, true);
this.checkPartKeys = checkKeys.checkPartKeys;
this.checkedKeys = checkKeys.checkedKeys;
this.treeNodesStates = checkKeys.treeNodesStates;
if (props.checkable && this.checkedKeysChange) {
if (props.checkStrictly) {
this.treeNodesStates = {};
loopAllChildren(props.children, (item, index, pos, keyOrPos, siblingPosition) => {
this.treeNodesStates[pos] = {
siblingPosition,
};
});
} else {
const checkedKeys = this.state.checkedKeys;
let checkKeys;
if (this.checkKeys && this._checkedKeys &&
this._checkedKeys.every((i, index) => checkedKeys[index] === i)) {
// if checkedKeys the same as _checkedKeys from onCheck, use _checkedKeys.
checkKeys = this.checkKeys;
} else {
const checkedPositions = [];
this.treeNodesStates = {};
loopAllChildren(props.children, (item, index, pos, keyOrPos, siblingPosition) => {
this.treeNodesStates[pos] = {
node: item,
key: keyOrPos,
checked: false,
checkPart: false,
siblingPosition,
};
if (checkedKeys.indexOf(keyOrPos) !== -1) {
this.treeNodesStates[pos].checked = true;
checkedPositions.push(pos);
}
});
// if the parent node's key exists, it all children node will be checked
handleCheckState(this.treeNodesStates, filterParentPosition(checkedPositions), true);
checkKeys = getCheckKeys(this.treeNodesStates);
}
this.checkPartKeys = checkKeys.checkPartKeys;
this.checkedKeys = checkKeys.checkedKeys;
}
}

return (
<ul {...domProps} unselectable ref="tree">
Expand Down
Loading

0 comments on commit 939e7fc

Please sign in to comment.