Skip to content

Commit

Permalink
Adjust loadData logic
Browse files Browse the repository at this point in the history
  • Loading branch information
zombieJ committed Aug 9, 2018
2 parents e889780 + bd7619e commit 4e69578
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 90 deletions.
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.13.1",
"version": "1.13.2",
"description": "tree ui component for react",
"keywords": [
"react",
Expand Down
67 changes: 37 additions & 30 deletions src/Tree.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -510,39 +510,46 @@ class Tree extends React.Component {
}
};

onNodeLoad = (treeNode) => {
const { loadData, onLoad } = this.props;
const { loadedKeys = [], loadingKeys = [] } = this.state;
const { eventKey } = treeNode.props;

if (!loadData || loadedKeys.indexOf(eventKey) !== -1 || loadingKeys.indexOf(eventKey) !== -1) {
return null;
}
onNodeLoad = treeNode => (
new Promise((resolve) => {
// We need to get the latest state of loading/loaded keys
this.setState(({ loadedKeys = [], loadingKeys = [] }) => {
const { loadData, onLoad } = this.props;
const { eventKey } = treeNode.props;

if (!loadData || loadedKeys.indexOf(eventKey) !== -1 || loadingKeys.indexOf(eventKey) !== -1) {
// react 15 will warn if return null
return {};
}

this.setState({
loadingKeys: arrAdd(loadingKeys, eventKey),
});
const promise = loadData(treeNode);
promise.then(() => {
const newLoadedKeys = arrAdd(this.state.loadedKeys, eventKey);
this.setUncontrolledState({
loadedKeys: newLoadedKeys,
});
this.setState({
loadingKeys: arrDel(this.state.loadingKeys, eventKey),
});
// Process load data
const promise = loadData(treeNode);
promise.then(() => {
const newLoadedKeys = arrAdd(this.state.loadedKeys, eventKey);
this.setUncontrolledState({
loadedKeys: newLoadedKeys,
});
this.setState({
loadingKeys: arrDel(this.state.loadingKeys, eventKey),
});

if (onLoad) {
const eventObj = {
event: 'load',
node: treeNode,
};
onLoad(newLoadedKeys, eventObj);
}

resolve();
});

if (onLoad) {
const eventObj = {
event: 'load',
node: treeNode,
return {
loadingKeys: arrAdd(loadingKeys, eventKey),
};
onLoad(newLoadedKeys, eventObj);
}
});

return promise;
};
});
})
);

onNodeExpand = (e, treeNode) => {
let { expandedKeys } = this.state;
Expand Down
4 changes: 3 additions & 1 deletion src/TreeNode.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,11 @@ class TreeNode extends React.Component {

// Load data to avoid default expanded tree without data
syncLoadData = (props) => {
const { expanded } = props;
const { expanded, loading } = props;
const { rcTree: { onNodeLoad } } = this.context;

if (loading) return;

// read from state to avoid loadData at same time
if (expanded && !this.isLeaf()) {
// We needn't reload data when has children in sync logic
Expand Down
26 changes: 1 addition & 25 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,30 +95,6 @@ export function mapChildren(children, func) {
return list;
}

/**
* Check position relation.
* @param parentPos
* @param childPos
* @param directly only directly parent can be true
* @returns {boolean}
*/
export function isParent(parentPos, childPos, directly = false) {
if (!parentPos || !childPos || parentPos.length > childPos.length) return false;

const parentPath = posToArr(parentPos);
const childPath = posToArr(childPos);

// Directly check
if (directly && parentPath.length !== childPath.length - 1) return false;

const len = parentPath.length;
for (let i = 0; i < len; i += 1) {
if (parentPath[i] !== childPath[i]) return false;
}

return true;
}

export function getDragNodesKeys(treeNodes, node) {
const { eventKey, pos } = node.props;
const dragNodesKeys = [];
Expand Down Expand Up @@ -256,7 +232,7 @@ export function parseCheckedKeys(keys) {
halfCheckedKeys: keys.halfChecked || undefined,
};
} else {
warning(false, '`CheckedKeys` is not an array or an object');
warning(false, '`checkedKeys` is not an array or an object');
return null;
}

Expand Down
97 changes: 65 additions & 32 deletions tests/TreeProps.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -401,49 +401,82 @@ describe('Tree Props', () => {
// defaultCheckedKeys - is already full test in Tree.spec.js
// defaultSelectedKeys - is already full test in Tree.spec.js

it('loadData', () => {
let called = 0;
describe('loadData', () => {
it('basic', () => {
let called = 0;

const handleLoadData = jest.fn();
const handleLoadData = jest.fn();

class Demo extends React.Component {
state = {
loaded: false,
};
class Demo extends React.Component {
state = {
loaded: false,
};

loadData = (...args) => {
called += 1;
handleLoadData(...args);
loadData = (...args) => {
called += 1;
handleLoadData(...args);

this.setState({ loaded: true });
this.setState({ loaded: true });

return Promise.resolve();
};
return Promise.resolve();
};

render() {
// Hide icon will still show the icon for loading status
return (
<Tree loadData={this.loadData} showIcon={false}>
<TreeNode key="0-0">
{this.state.loaded ? <TreeNode key="0-0-0" /> : null}
</TreeNode>
</Tree>
);
render() {
// Hide icon will still show the icon for loading status
return (
<Tree loadData={this.loadData} showIcon={false}>
<TreeNode key="0-0">
{this.state.loaded ? <TreeNode key="0-0-0" /> : null}
</TreeNode>
</Tree>
);
}
}
}

const wrapper = mount(<Demo />);
const wrapper = mount(<Demo />);

expect(handleLoadData).not.toBeCalled();
expect(handleLoadData).not.toBeCalled();

const switcher = wrapper.find('.rc-tree-switcher');
const node = wrapper.find(TreeNode).instance();
switcher.simulate('click');

return timeoutPromise().then(() => {
expect(handleLoadData).toBeCalledWith(node);
expect(called).toBe(1);
expect(renderToJson(wrapper.render())).toMatchSnapshot();
});
});

const switcher = wrapper.find('.rc-tree-switcher');
const node = wrapper.find(TreeNode).instance();
switcher.simulate('click');
// https://github.com/ant-design/ant-design/issues/11689#issuecomment-411712770
it('with expandedKeys', () => {
let called = 0;
const keys = {};
const loadData = ({ props: { eventKey } }) => {
keys[eventKey] = (keys[eventKey] || 0) + 1;

return timeoutPromise().then(() => {
expect(handleLoadData).toBeCalledWith(node);
expect(called).toBe(1);
expect(renderToJson(wrapper.render())).toMatchSnapshot();
return new Promise(() => {
called += 1;
});
};

mount(
<Tree
loadData={loadData}
expandedKeys={['0', '1', '2']}
>
<TreeNode key="0" />
<TreeNode key="1" />
<TreeNode key="2" />
</Tree>
);

return timeoutPromise().then(() => {
expect(called).toBe(3);
expect(keys[0]).toBe(1);
expect(keys[1]).toBe(1);
expect(keys[2]).toBe(1);
});
});
});

Expand Down
2 changes: 1 addition & 1 deletion tests/__snapshots__/TreeProps.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@ exports[`Tree Props invalidate checkedKeys number 1`] = `
</ul>
`;

exports[`Tree Props loadData 1`] = `
exports[`Tree Props loadData basic 1`] = `
<ul
class="rc-tree"
role="tree"
Expand Down

0 comments on commit 4e69578

Please sign in to comment.