diff --git a/src/hooks/useFilterTreeData.ts b/src/hooks/useFilterTreeData.ts index 9a16b19d..2f764b30 100644 --- a/src/hooks/useFilterTreeData.ts +++ b/src/hooks/useFilterTreeData.ts @@ -2,22 +2,18 @@ import * as React from 'react'; import type { DefaultOptionType, InternalFieldName, TreeSelectProps } from '../TreeSelect'; import { fillLegacyProps } from '../utils/legacyUtil'; -type GetFuncType = T extends boolean ? never : T; -type FilterFn = GetFuncType; +type FilterFn = NonNullable; -export default ( +const useFilterTreeData = ( treeData: DefaultOptionType[], searchValue: string, - { - treeNodeFilterProp, - filterTreeNode, - fieldNames, - }: { + options: { fieldNames: InternalFieldName; treeNodeFilterProp: string; filterTreeNode: TreeSelectProps['filterTreeNode']; }, ) => { + const { fieldNames, treeNodeFilterProp, filterTreeNode } = options; const { children: fieldChildren } = fieldNames; return React.useMemo(() => { @@ -31,24 +27,24 @@ export default ( : (_, dataNode) => String(dataNode[treeNodeFilterProp]).toUpperCase().includes(searchValue.toUpperCase()); - function dig(list: DefaultOptionType[], keepAll: boolean = false) { - return list.reduce((total, dataNode) => { - const children = dataNode[fieldChildren]; + const filterTreeNodes = (nodes: DefaultOptionType[], keepAll = false): DefaultOptionType[] => + nodes.reduce((filtered, node) => { + const children = node[fieldChildren]; + const isMatch = keepAll || filterOptionFunc(searchValue, fillLegacyProps(node)); + const filteredChildren = filterTreeNodes(children || [], isMatch); - const match = keepAll || filterOptionFunc(searchValue, fillLegacyProps(dataNode)); - const childList = dig(children || [], match); - - if (match || childList.length) { - total.push({ - ...dataNode, + if (isMatch || filteredChildren.length) { + filtered.push({ + ...node, isLeaf: undefined, - [fieldChildren]: childList, + [fieldChildren]: filteredChildren, }); } - return total; + return filtered; }, []); - } - return dig(treeData); + return filterTreeNodes(treeData); }, [treeData, searchValue, fieldChildren, treeNodeFilterProp, filterTreeNode]); }; + +export default useFilterTreeData; diff --git a/src/hooks/useTreeData.ts b/src/hooks/useTreeData.ts index 26ffbebd..96ea50ad 100644 --- a/src/hooks/useTreeData.ts +++ b/src/hooks/useTreeData.ts @@ -3,45 +3,35 @@ import type { DataNode, SimpleModeConfig } from '../interface'; import { convertChildrenToData } from '../utils/legacyUtil'; import type { DefaultOptionType } from '../TreeSelect'; -function parseSimpleTreeData( - treeData: DataNode[], - { id, pId, rootPId }: SimpleModeConfig, -): DataNode[] { - const keyNodes = {}; - const rootNodeList = []; - - // Fill in the map - const nodeList = treeData.map(node => { - const clone = { ...node }; - const key = clone[id]; - keyNodes[key] = clone; - clone.key = clone.key || key; - return clone; +function buildTreeStructure(nodes: DataNode[], config: SimpleModeConfig): DataNode[] { + const { id, pId, rootPId } = config; + const nodeMap = new Map(); + const rootNodes: DataNode[] = []; + + nodes.forEach(node => { + const nodeKey = node[id]; + const clonedNode = { ...node, key: node.key || nodeKey }; + nodeMap.set(nodeKey, clonedNode); }); - // Connect tree - nodeList.forEach(node => { + nodeMap.forEach(node => { const parentKey = node[pId]; - const parent = keyNodes[parentKey]; + const parent = nodeMap.get(parentKey); - // Fill parent if (parent) { parent.children = parent.children || []; parent.children.push(node); - } - - // Fill root tree node - if (parentKey === rootPId || (!parent && rootPId === null)) { - rootNodeList.push(node); + } else if (parentKey === rootPId || rootPId === null) { + rootNodes.push(node); } }); - return rootNodeList; + return rootNodes; } /** - * Convert `treeData` or `children` into formatted `treeData`. - * Will not re-calculate if `treeData` or `children` not change. + * 将 `treeData` 或 `children` 转换为格式化的 `treeData`。 + * 如果 `treeData` 或 `children` 没有变化,则不会重新计算。 */ export default function useTreeData( treeData: DataNode[], @@ -50,14 +40,16 @@ export default function useTreeData( ): DefaultOptionType[] { return React.useMemo(() => { if (treeData) { - return simpleMode - ? parseSimpleTreeData(treeData, { - id: 'id', - pId: 'pId', - rootPId: null, - ...(simpleMode !== true ? simpleMode : {}), - }) - : treeData; + if (simpleMode) { + const config: SimpleModeConfig = { + id: 'id', + pId: 'pId', + rootPId: null, + ...(typeof simpleMode === 'object' ? simpleMode : {}), + }; + return buildTreeStructure(treeData, config); + } + return treeData; } return convertChildrenToData(children); diff --git a/src/utils/valueUtil.ts b/src/utils/valueUtil.ts index 9e940a55..a66ba045 100644 --- a/src/utils/valueUtil.ts +++ b/src/utils/valueUtil.ts @@ -10,13 +10,10 @@ export function toArray(value: T | T[]): T[] { export function fillFieldNames(fieldNames?: FieldNames) { const { label, value, children } = fieldNames || {}; - - const mergedValue = value || 'value'; - return { _title: label ? [label] : ['title', 'label'], - value: mergedValue, - key: mergedValue, + value: value || 'value', + key: value || 'value', children: children || 'children', }; }