From 0a887aff844fbe565b47ff0067c4b1daba789159 Mon Sep 17 00:00:00 2001 From: luatsoft Date: Fri, 23 Nov 2018 17:09:00 +0800 Subject: [PATCH] Not loadData when tree select is in filter (#133) fix ant-design/ant-design#13245 --- examples/basic.js | 2 +- src/Base/BasePopup.jsx | 35 ++++++++++++++++++++----- src/Select.jsx | 24 ++++++++++++----- tests/Select.SearchInput.spec.js | 17 ++++++++++++ tests/__snapshots__/Select.spec.js.snap | 2 +- 5 files changed, 65 insertions(+), 15 deletions(-) diff --git a/examples/basic.js b/examples/basic.js index 03a4eb7..fc33cd2 100644 --- a/examples/basic.js +++ b/examples/basic.js @@ -87,7 +87,7 @@ class Demo extends React.Component { } onSearch = (value) => { - console.log(value, arguments); + console.log('Do Search:', value, arguments); this.setState({ searchValue: value }); } diff --git a/src/Base/BasePopup.jsx b/src/Base/BasePopup.jsx index ed0d93b..baac588 100644 --- a/src/Base/BasePopup.jsx +++ b/src/Base/BasePopup.jsx @@ -66,13 +66,18 @@ class BasePopup extends React.Component { this.state = { keyList: [], expandedKeyList, + // Cache `expandedKeyList` when tree is in filter. This is used in `getDerivedStateFromProps` + cachedExpandedKeyList: [], // eslint-disable-line react/no-unused-state loadedKeys: [], }; } static getDerivedStateFromProps(nextProps, prevState) { - const { prevProps = {}, loadedKeys } = prevState || {}; - const { valueList, valueEntities, keyEntities, filteredTreeNodes } = nextProps; + const { prevProps = {}, loadedKeys, expandedKeyList, cachedExpandedKeyList } = prevState || {}; + const { + valueList, valueEntities, keyEntities, + treeExpandedKeys, filteredTreeNodes, searchValue + } = nextProps; const newState = { prevProps: nextProps, @@ -88,7 +93,7 @@ class BasePopup extends React.Component { // Show all when tree is in filter mode if ( - !nextProps.treeExpandedKeys && + !treeExpandedKeys && filteredTreeNodes && filteredTreeNodes.length && filteredTreeNodes !== prevProps.filteredTreeNodes @@ -96,9 +101,17 @@ class BasePopup extends React.Component { newState.expandedKeyList = Object.keys(keyEntities); } + // Cache `expandedKeyList` when filter set + if (searchValue && !prevProps.searchValue) { + newState.cachedExpandedKeyList = expandedKeyList; + } else if (!searchValue && prevProps.searchValue && !treeExpandedKeys) { + newState.expandedKeyList = cachedExpandedKeyList || []; + newState.cachedExpandedKeyList = []; + } + // Use expandedKeys if provided - if (prevProps.treeExpandedKeys !== nextProps.treeExpandedKeys) { - newState.expandedKeyList = nextProps.treeExpandedKeys; + if (prevProps.treeExpandedKeys !== treeExpandedKeys) { + newState.expandedKeyList = treeExpandedKeys; } // Clean loadedKeys if key not exist in keyEntities anymore @@ -126,6 +139,15 @@ class BasePopup extends React.Component { this.setState({ loadedKeys }); }; + /** + * Not pass `loadData` when searching. To avoid loop ajax call makes browser crash. + */ + getLoadData = () => { + const { loadData, searchValue } = this.props; + if (searchValue) return null; + return loadData; + }; + /** * This method pass to Tree component which is used for add filtered class * in TreeNode > li @@ -157,7 +179,6 @@ class BasePopup extends React.Component { prefixCls, treeNodes, filteredTreeNodes, treeIcon, treeLine, treeCheckable, treeCheckStrictly, multiple, - loadData, ariaId, renderSearch, switcherIcon, @@ -168,6 +189,8 @@ class BasePopup extends React.Component { onTreeNodeCheck, } } = this.context; + const loadData = this.getLoadData(); + const treeProps = {}; if (treeCheckable) { diff --git a/src/Select.jsx b/src/Select.jsx index 1a70acb..0349a60 100644 --- a/src/Select.jsx +++ b/src/Select.jsx @@ -541,10 +541,10 @@ class Select extends React.Component { onValueTrigger = (isAdd, nodeList, nodeEventInfo, nodeExtraInfo) => { const { node } = nodeEventInfo; const { value } = node.props; - const { missValueList, valueEntities, keyEntities } = this.state; + const { missValueList, valueEntities, keyEntities, searchValue } = this.state; const { disabled, inputValue, - treeNodeLabelProp, onSelect, + treeNodeLabelProp, onSelect, onSearch, treeCheckable, treeCheckStrictly, autoClearSearchValue, } = this.props; const label = node.props[treeNodeLabelProp]; @@ -606,11 +606,21 @@ class Select extends React.Component { } // Clean up `searchValue` when this prop is set - if (!this.isSearchValueControlled() && (autoClearSearchValue || inputValue === null)) { - this.setUncontrolledState({ - searchValue: '', - filteredTreeNodes: null, - }); + if (autoClearSearchValue || inputValue === null) { + // Clean state `searchValue` if uncontrolled + if (!this.isSearchValueControlled()) { + this.setUncontrolledState({ + searchValue: '', + filteredTreeNodes: null, + }); + } + + // Trigger onSearch if `searchValue` to be empty. + // We should also trigger onSearch with empty string here + // since if user use `treeExpandedKeys`, it need user have the ability to reset it. + if (onSearch && searchValue && searchValue.length) { + onSearch(''); + } } // [Legacy] Provide extra info diff --git a/tests/Select.SearchInput.spec.js b/tests/Select.SearchInput.spec.js index 34ec6c9..3615f4d 100644 --- a/tests/Select.SearchInput.spec.js +++ b/tests/Select.SearchInput.spec.js @@ -59,4 +59,21 @@ describe('TreeSelect.SearchInput', () => { }, 10); }); }); + + it('select item will clean searchInput', () => { + const onSearch = jest.fn(); + + const wrapper = mount( + + + + ); + + wrapper.find('.rc-tree-select-search__field').simulate('change', { target: { value: 'test' } }); + expect(onSearch).toBeCalledWith('test'); + onSearch.mockReset(); + + wrapper.find('.rc-tree-select-tree-node-content-wrapper').simulate('click'); + expect(onSearch).toBeCalledWith(''); + }); }); diff --git a/tests/__snapshots__/Select.spec.js.snap b/tests/__snapshots__/Select.spec.js.snap index f87781f..ad828f0 100644 --- a/tests/__snapshots__/Select.spec.js.snap +++ b/tests/__snapshots__/Select.spec.js.snap @@ -472,7 +472,7 @@ exports[`TreeSelect.basic search nodes check tree changed by filter 2`] = `