From 971a4c1ad4c9ecaa10e11ac50484b2f216252f17 Mon Sep 17 00:00:00 2001 From: zombiej Date: Wed, 22 Jul 2020 17:29:23 +0800 Subject: [PATCH 1/2] use hooks --- examples/treeNodeLabelProp.tsx | 24 ++++++++++++++++++++++++ package.json | 4 ++-- src/TreeSelect.tsx | 6 ++++-- 3 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 examples/treeNodeLabelProp.tsx diff --git a/examples/treeNodeLabelProp.tsx b/examples/treeNodeLabelProp.tsx new file mode 100644 index 00000000..b111beaf --- /dev/null +++ b/examples/treeNodeLabelProp.tsx @@ -0,0 +1,24 @@ +import '../assets/index.less'; +import React from 'react'; +import TreeSelect from '../src'; + +const treeData = [ + { + title: 'a list is option only', + showTitle: 'Node2', + value: '0-1', + }, +]; + +function Demo() { + return ( + + ); +} + +export default Demo; diff --git a/package.json b/package.json index 477b26e2..3380dbad 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@babel/runtime": "^7.10.1", "classnames": "2.x", "rc-select": "^11.0.4", - "rc-tree": "^3.6.0", - "rc-util": "^5.0.1" + "rc-tree": "^3.8.0", + "rc-util": "^5.0.5" } } diff --git a/src/TreeSelect.tsx b/src/TreeSelect.tsx index ce8f4b25..b2fd3ca1 100644 --- a/src/TreeSelect.tsx +++ b/src/TreeSelect.tsx @@ -5,6 +5,7 @@ import { convertDataToEntities } from 'rc-tree/lib/utils/treeUtil'; import { conductCheck } from 'rc-tree/lib/utils/conductUtil'; import { IconType } from 'rc-tree/lib/interface'; import { FilterFunc, INTERNAL_PROPS_MARK } from 'rc-select/lib/interface/generator'; +import useMergedState from 'rc-util/lib/hooks/useMergedState'; import warning from 'rc-util/lib/warning'; import OptionList from './OptionList'; import TreeNode from './TreeNode'; @@ -235,8 +236,9 @@ const RefTreeSelect = React.forwardRef((props, }, [mergedTreeData, treeCheckable, treeCheckStrictly]); // ========================= Value ========================= - const [value, setValue] = React.useState(props.defaultValue); - const mergedValue = 'value' in props ? props.value : value; + const [mergedValue, setValue] = useMergedState(props.defaultValue, { + value: props.value, + }); /** Get `missingRawValues` which not exist in the tree yet */ const splitRawValues = (newRawValues: RawValueType[]) => { From a3d2762b11fa06096da2b1fc3ca2c77b15e5e2ed Mon Sep 17 00:00:00 2001 From: zombiej Date: Wed, 22 Jul 2020 17:53:43 +0800 Subject: [PATCH 2/2] fix: treeNodeLabelProp should only work on result value --- examples/treeNodeLabelProp.tsx | 19 +++++++++++------- src/TreeSelect.tsx | 35 +++++++++++++++++++--------------- tests/Select.tree.spec.js | 25 ++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 22 deletions(-) diff --git a/examples/treeNodeLabelProp.tsx b/examples/treeNodeLabelProp.tsx index b111beaf..b679d760 100644 --- a/examples/treeNodeLabelProp.tsx +++ b/examples/treeNodeLabelProp.tsx @@ -1,6 +1,6 @@ import '../assets/index.less'; import React from 'react'; -import TreeSelect from '../src'; +import TreeSelect, { TreeNode } from '../src'; const treeData = [ { @@ -12,12 +12,17 @@ const treeData = [ function Demo() { return ( - + <> + + + + + ); } diff --git a/src/TreeSelect.tsx b/src/TreeSelect.tsx index b2fd3ca1..4701ad4d 100644 --- a/src/TreeSelect.tsx +++ b/src/TreeSelect.tsx @@ -1,4 +1,5 @@ -import React from 'react'; +import * as React from 'react'; +import { useMemo } from 'react'; import generateSelector, { SelectProps, RefSelectProps } from 'rc-select/lib/generate'; import { getLabeledValue } from 'rc-select/lib/utils/valueUtil'; import { convertDataToEntities } from 'rc-tree/lib/utils/treeUtil'; @@ -207,28 +208,32 @@ const RefTreeSelect = React.forwardRef((props, // ======================= Tree Data ======================= // Legacy both support `label` or `title` if not set. // We have to fallback to function to handle this + const getTreeNodeTitle = (node: DataNode): React.ReactNode => { + if (!treeData) { + return node.title; + } + return node.label || node.title; + }; + const getTreeNodeLabelProp = (node: DataNode): React.ReactNode => { if (treeNodeLabelProp) { return node[treeNodeLabelProp]; } - if (!treeData) { - return node.title; - } - return node.label || node.title; + return getTreeNodeTitle(node); }; const mergedTreeData = useTreeData(treeData, children, { - getLabelProp: getTreeNodeLabelProp, + getLabelProp: getTreeNodeTitle, simpleMode: treeDataSimpleMode, }); - const flattedOptions = React.useMemo(() => flattenOptions(mergedTreeData), [mergedTreeData]); + const flattedOptions = useMemo(() => flattenOptions(mergedTreeData), [mergedTreeData]); const [cacheKeyMap, cacheValueMap] = useKeyValueMap(flattedOptions); const [getEntityByKey, getEntityByValue] = useKeyValueMapping(cacheKeyMap, cacheValueMap); // Only generate keyEntities for check conduction when is `treeCheckable` - const { keyEntities: conductKeyEntities } = React.useMemo(() => { + const { keyEntities: conductKeyEntities } = useMemo(() => { if (treeConduction) { return convertDataToEntities(mergedTreeData as any); } @@ -236,7 +241,7 @@ const RefTreeSelect = React.forwardRef((props, }, [mergedTreeData, treeCheckable, treeCheckStrictly]); // ========================= Value ========================= - const [mergedValue, setValue] = useMergedState(props.defaultValue, { + const [value, setValue] = useMergedState(props.defaultValue, { value: props.value, }); @@ -257,11 +262,11 @@ const RefTreeSelect = React.forwardRef((props, return { missingRawValues, existRawValues }; }; - const [rawValues, rawHalfCheckedKeys]: [RawValueType[], RawValueType[]] = React.useMemo(() => { + const [rawValues, rawHalfCheckedKeys]: [RawValueType[], RawValueType[]] = useMemo(() => { const valueHalfCheckedKeys: RawValueType[] = []; const newRawValues: RawValueType[] = []; - toArray(mergedValue).forEach(item => { + toArray(value).forEach(item => { if (item && typeof item === 'object' && 'value' in item) { if (item.halfChecked && treeCheckStrictly) { const entity = getEntityByValue(item.value); @@ -286,10 +291,10 @@ const RefTreeSelect = React.forwardRef((props, ]; } return [newRawValues, valueHalfCheckedKeys]; - }, [mergedValue, mergedMultiple, mergedLabelInValue, treeCheckable, treeCheckStrictly]); + }, [value, mergedMultiple, mergedLabelInValue, treeCheckable, treeCheckStrictly]); const selectValues = useSelectValues(rawValues, { treeConduction, - value: mergedValue, + value, showCheckedStrategy, conductKeyEntities, getEntityByValue, @@ -328,7 +333,7 @@ const RefTreeSelect = React.forwardRef((props, }; let returnValues = mergedLabelInValue - ? getRawValueLabeled(eventValues, mergedValue, getEntityByValue, getTreeNodeLabelProp) + ? getRawValueLabeled(eventValues, value, getEntityByValue, getTreeNodeLabelProp) : eventValues; // We need fill half check back @@ -342,7 +347,7 @@ const RefTreeSelect = React.forwardRef((props, returnValues = [ ...(returnValues as LabelValueType[]), - ...getRawValueLabeled(halfValues, mergedValue, getEntityByValue, getTreeNodeLabelProp), + ...getRawValueLabeled(halfValues, value, getEntityByValue, getTreeNodeLabelProp), ]; } diff --git a/tests/Select.tree.spec.js b/tests/Select.tree.spec.js index 89a7d458..6628dea3 100644 --- a/tests/Select.tree.spec.js +++ b/tests/Select.tree.spec.js @@ -100,4 +100,29 @@ describe('TreeSelect.tree', () => { expect(wrapper.getSelection(0).text()).toEqual('empty string'); }); + + describe('treeNodeLabelProp', () => { + [ + { name: 'treeDate', treeData: [{ title: 'a light', op: 'Light', value: 'light' }] }, + { + name: 'children', + children: , + }, + ].forEach(({ name, ...restProps }) => { + it(name, () => { + const wrapper = mount( + , + ); + + expect(wrapper.find('.rc-tree-select-tree-title').text()).toEqual('a light'); + expect(wrapper.find('.rc-tree-select-selection-item').text()).toEqual('Light'); + }); + }); + }); });