Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: always change treeProps.expandedKeys to avoid wrong loadling data #576

Merged
merged 13 commits into from
Oct 24, 2024
12 changes: 11 additions & 1 deletion src/OptionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,16 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
onKeyUp: () => {},
}));


const loadDataFun = React.useMemo(() => {
// should not pass `loadData` when expandedKeys is not changed
if (!searchValue && searchExpandedKeys?.length && !mergedExpandedKeys) {
bbb169 marked this conversation as resolved.
Show resolved Hide resolved
return null
}

return searchValue ? null : (loadData as any)
}, [searchValue])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}, [searchValue])
}, [searchValue, searchExpandedKeys, mergedExpandedKeys]);


// ========================== Render ==========================
if (memoTreeData.length === 0) {
return (
Expand Down Expand Up @@ -237,7 +247,7 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
showIcon={showTreeIcon}
switcherIcon={switcherIcon}
showLine={treeLine}
loadData={searchValue ? null : (loadData as any)}
loadData={loadDataFun}
motion={treeMotion}
activeKey={activeKey}
// We handle keys by out instead tree self
Expand Down
113 changes: 81 additions & 32 deletions tests/Select.SearchInput.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable no-undef */
import React, { useState } from 'react';
import { mount } from 'enzyme';
import TreeSelect, { TreeNode } from '../src';
import TreeSelect, { TreeNode, TreeSelectProps } from '../src';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

TreeSelectProps 未在测试用例中使用,建议移除导入。

  • 文件: tests/Select.SearchInput.spec.js 第4行
🔗 Analysis chain

导入 TreeSelectProps 是个好主意。

导入 TreeSelectProps 可以增强类型检查,提高代码的可靠性。这是一个很好的改进。

请确保在测试用例中正确使用了 TreeSelectProps。可以运行以下命令来验证:


由于之前的命令未能识别 typescript 类型,生成以下脚本以重新验证 TreeSelectProps 的使用情况:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 描述:验证 TreeSelectProps 的使用情况
rg --type typescript "TreeSelectProps" tests/Select.SearchInput.spec.js

Length of output: 106


Script:

#!/bin/bash
# 描述:验证 TreeSelectProps 的使用情况
rg "TreeSelectProps" tests/Select.SearchInput.spec.js

Length of output: 117


describe('TreeSelect.SearchInput', () => {
it('select item will clean searchInput', () => {
Expand All @@ -19,12 +19,7 @@ describe('TreeSelect.SearchInput', () => {

wrapper.selectNode();
expect(onSearch).not.toHaveBeenCalled();
expect(
wrapper
.find('input')
.first()
.props().value,
).toBeFalsy();
expect(wrapper.find('input').first().props().value).toBeFalsy();
});

it('expandedKeys', () => {
Expand All @@ -51,10 +46,7 @@ describe('TreeSelect.SearchInput', () => {
expect(wrapper.find('NodeList').prop('expandedKeys')).toEqual(['bamboo', 'light']);

function search(value) {
wrapper
.find('input')
.first()
.simulate('change', { target: { value } });
wrapper.find('input').first().simulate('change', { target: { value } });
wrapper.update();
}

Expand Down Expand Up @@ -85,8 +77,8 @@ describe('TreeSelect.SearchInput', () => {
{ id: 1, pId: 0, value: '1', title: 'Expand to load' },
{ id: 2, pId: 0, value: '2', title: 'Expand to load' },
{ id: 3, pId: 0, value: '3', title: 'Tree Node', isLeaf: true },
])
}
]);
};

const genTreeNode = (parentId, isLeaf = false) => {
const random = Math.random().toString(36).substring(2, 6);
Expand All @@ -100,22 +92,16 @@ describe('TreeSelect.SearchInput', () => {
};

const onLoadData = ({ id, ...rest }) =>
new Promise((resolve) => {
setTimeout(() => {
called += 1;
handleLoadData({ id, ...rest });
setTreeData(
treeData.concat([
genTreeNode(id, false),
genTreeNode(id, true),
genTreeNode(id, true),
])
);
resolve(undefined);
}, 300);
new Promise(resolve => {
called += 1;
handleLoadData({ id, ...rest });
setTreeData(
treeData.concat([genTreeNode(id, false), genTreeNode(id, true), genTreeNode(id, true)]),
);
resolve(undefined);
});

const onChange = (newValue) => {
const onChange = newValue => {
setValue(newValue);
};

Expand All @@ -130,7 +116,6 @@ describe('TreeSelect.SearchInput', () => {
treeData={treeData}
treeNodeFilterProp="title"
showSearch
filterTreeNode={false}
/>
<button onClick={addDefaultTreeData}>设置数据</button>
</>
Expand All @@ -141,10 +126,7 @@ describe('TreeSelect.SearchInput', () => {
expect(handleLoadData).not.toHaveBeenCalled();

function search(value) {
wrapper
.find('input')
.first()
.simulate('change', { target: { value } });
wrapper.find('input').first().simulate('change', { target: { value } });
wrapper.update();
}
search('Tree Node');
Expand All @@ -165,5 +147,72 @@ describe('TreeSelect.SearchInput', () => {
search('');
expect(handleLoadData).not.toHaveBeenCalled();
expect(called).toBe(0);

search('ex');
const nodes = wrapper.find(`[title="${'Expand to load'}"]`).hostNodes();
nodes.first().simulate('click');
expect(called).toBe(0); // should not trrigger all nodes to load data
});

it('not trigger loadData when clearing the search', () => {
let called = 0;
const handleLoadData = jest.fn();
const Demo = () => {
const [value, setValue] = useState();

const genTreeNode = (parentId, isLeaf = false) => {
const random = Math.random().toString(36).substring(2, 6);
return {
id: random,
pId: parentId,
value: random,
title: isLeaf ? 'Tree Node' : 'Expand to load',
isLeaf,
};
};

const onLoadData = ({ id, ...rest }) =>
new Promise(resolve => {
called += 1;
handleLoadData({ id, ...rest });
setTreeData(
treeData.concat([genTreeNode(id, false), genTreeNode(id, true), genTreeNode(id, true)]),
);
resolve(undefined);
});

const onChange = newValue => {
setValue(newValue);
};

return (
<TreeSelect
treeDataSimpleMode
value={value}
placeholder="Please select"
onChange={onChange}
loadData={onLoadData}
treeData={[
{ id: 1, pId: 0, value: '1', title: 'Expand to load' },
{ id: 2, pId: 0, value: '2', title: 'Expand to load' },
{ id: 3, pId: 0, value: '3', title: 'Tree Node', isLeaf: true },
]}
treeNodeFilterProp="title"
treeExpandAction="click"
showSearch
/>
);
};
const wrapper = mount(<Demo />);

function search(value) {
wrapper.find('input').first().simulate('change', { target: { value } });
wrapper.update();
}

search('ex');
const nodes = wrapper.find(`[title="${'Expand to load'}"]`).hostNodes();
nodes.first().simulate('click');
expect(called).toBe(1);
afc163 marked this conversation as resolved.
Show resolved Hide resolved
});
});