Skip to content

Commit 63d472f

Browse files
authored
refactor: refactor utils and hooks (#585)
1 parent 72d007a commit 63d472f

File tree

5 files changed

+87
-107
lines changed

5 files changed

+87
-107
lines changed

src/hooks/useCache.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ export default (values: LabeledValueType[]): [LabeledValueType[]] => {
1515
const valueLabelsCache = new Map<SafeKey, React.ReactNode>();
1616

1717
const filledValues = values.map(item => {
18-
const { value } = item;
19-
const mergedLabel = item.label ?? valueLabels.get(value);
18+
const { value, label } = item;
19+
const mergedLabel = label ?? valueLabels.get(value);
2020

2121
// Save in cache
2222
valueLabelsCache.set(value, mergedLabel);

src/hooks/useCheckedKeys.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,32 @@ import type { DataEntity } from 'rc-tree/lib/interface';
33
import { conductCheck } from 'rc-tree/lib/utils/conductUtil';
44
import type { LabeledValueType, SafeKey } from '../interface';
55

6-
export default (
6+
const useCheckedKeys = (
77
rawLabeledValues: LabeledValueType[],
88
rawHalfCheckedValues: LabeledValueType[],
99
treeConduction: boolean,
1010
keyEntities: Record<SafeKey, DataEntity>,
11-
) =>
12-
React.useMemo(() => {
13-
let checkedKeys: SafeKey[] = rawLabeledValues.map(({ value }) => value);
14-
let halfCheckedKeys: SafeKey[] = rawHalfCheckedValues.map(({ value }) => value);
11+
) => {
12+
return React.useMemo(() => {
13+
const extractValues = (values: LabeledValueType[]): SafeKey[] =>
14+
values.map(({ value }) => value);
15+
16+
const checkedKeys = extractValues(rawLabeledValues);
17+
const halfCheckedKeys = extractValues(rawHalfCheckedValues);
1518

1619
const missingValues = checkedKeys.filter(key => !keyEntities[key]);
1720

21+
let finalCheckedKeys = checkedKeys;
22+
let finalHalfCheckedKeys = halfCheckedKeys;
23+
1824
if (treeConduction) {
19-
({ checkedKeys, halfCheckedKeys } = conductCheck(checkedKeys, true, keyEntities));
25+
const conductResult = conductCheck(checkedKeys, true, keyEntities);
26+
finalCheckedKeys = conductResult.checkedKeys;
27+
finalHalfCheckedKeys = conductResult.halfCheckedKeys;
2028
}
2129

22-
return [
23-
// Checked keys should fill with missing keys which should de-duplicated
24-
Array.from(new Set([...missingValues, ...checkedKeys])),
25-
// Half checked keys
26-
halfCheckedKeys,
27-
];
30+
return [Array.from(new Set([...missingValues, ...finalCheckedKeys])), finalHalfCheckedKeys];
2831
}, [rawLabeledValues, rawHalfCheckedValues, treeConduction, keyEntities]);
32+
};
33+
34+
export default useCheckedKeys;

src/hooks/useFilterTreeData.ts

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,59 +2,49 @@ import * as React from 'react';
22
import type { DefaultOptionType, InternalFieldName, TreeSelectProps } from '../TreeSelect';
33
import { fillLegacyProps } from '../utils/legacyUtil';
44

5-
type GetFuncType<T> = T extends boolean ? never : T;
6-
type FilterFn = GetFuncType<TreeSelectProps['filterTreeNode']>;
5+
type FilterFn = NonNullable<TreeSelectProps['filterTreeNode']>;
76

8-
export default (
7+
const useFilterTreeData = (
98
treeData: DefaultOptionType[],
109
searchValue: string,
11-
{
12-
treeNodeFilterProp,
13-
filterTreeNode,
14-
fieldNames,
15-
}: {
10+
options: {
1611
fieldNames: InternalFieldName;
1712
treeNodeFilterProp: string;
1813
filterTreeNode: TreeSelectProps['filterTreeNode'];
1914
},
2015
) => {
16+
const { fieldNames, treeNodeFilterProp, filterTreeNode } = options;
2117
const { children: fieldChildren } = fieldNames;
2218

2319
return React.useMemo(() => {
2420
if (!searchValue || filterTreeNode === false) {
2521
return treeData;
2622
}
2723

28-
let filterOptionFunc: FilterFn;
29-
if (typeof filterTreeNode === 'function') {
30-
filterOptionFunc = filterTreeNode;
31-
} else {
32-
const upperStr = searchValue.toUpperCase();
33-
filterOptionFunc = (_, dataNode) => {
34-
const value = dataNode[treeNodeFilterProp];
35-
36-
return String(value).toUpperCase().includes(upperStr);
37-
};
38-
}
39-
40-
function dig(list: DefaultOptionType[], keepAll: boolean = false) {
41-
return list.reduce<DefaultOptionType[]>((total, dataNode) => {
42-
const children = dataNode[fieldChildren];
43-
44-
const match = keepAll || filterOptionFunc(searchValue, fillLegacyProps(dataNode));
45-
const childList = dig(children || [], match);
46-
47-
if (match || childList.length) {
48-
total.push({
49-
...dataNode,
24+
const filterOptionFunc: FilterFn =
25+
typeof filterTreeNode === 'function'
26+
? filterTreeNode
27+
: (_, dataNode) =>
28+
String(dataNode[treeNodeFilterProp]).toUpperCase().includes(searchValue.toUpperCase());
29+
30+
const filterTreeNodes = (nodes: DefaultOptionType[], keepAll = false): DefaultOptionType[] =>
31+
nodes.reduce<DefaultOptionType[]>((filtered, node) => {
32+
const children = node[fieldChildren];
33+
const isMatch = keepAll || filterOptionFunc(searchValue, fillLegacyProps(node));
34+
const filteredChildren = filterTreeNodes(children || [], isMatch);
35+
36+
if (isMatch || filteredChildren.length) {
37+
filtered.push({
38+
...node,
5039
isLeaf: undefined,
51-
[fieldChildren]: childList,
40+
[fieldChildren]: filteredChildren,
5241
});
5342
}
54-
return total;
43+
return filtered;
5544
}, []);
56-
}
5745

58-
return dig(treeData);
46+
return filterTreeNodes(treeData);
5947
}, [treeData, searchValue, fieldChildren, treeNodeFilterProp, filterTreeNode]);
6048
};
49+
50+
export default useFilterTreeData;

src/hooks/useTreeData.ts

Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,35 @@ import type { DataNode, SimpleModeConfig } from '../interface';
33
import { convertChildrenToData } from '../utils/legacyUtil';
44
import type { DefaultOptionType } from '../TreeSelect';
55

6-
function parseSimpleTreeData(
7-
treeData: DataNode[],
8-
{ id, pId, rootPId }: SimpleModeConfig,
9-
): DataNode[] {
10-
const keyNodes = {};
11-
const rootNodeList = [];
12-
13-
// Fill in the map
14-
const nodeList = treeData.map(node => {
15-
const clone = { ...node };
16-
const key = clone[id];
17-
keyNodes[key] = clone;
18-
clone.key = clone.key || key;
19-
return clone;
6+
function buildTreeStructure(nodes: DataNode[], config: SimpleModeConfig): DataNode[] {
7+
const { id, pId, rootPId } = config;
8+
const nodeMap = new Map<string, DataNode>();
9+
const rootNodes: DataNode[] = [];
10+
11+
nodes.forEach(node => {
12+
const nodeKey = node[id];
13+
const clonedNode = { ...node, key: node.key || nodeKey };
14+
nodeMap.set(nodeKey, clonedNode);
2015
});
2116

22-
// Connect tree
23-
nodeList.forEach(node => {
17+
nodeMap.forEach(node => {
2418
const parentKey = node[pId];
25-
const parent = keyNodes[parentKey];
19+
const parent = nodeMap.get(parentKey);
2620

27-
// Fill parent
2821
if (parent) {
2922
parent.children = parent.children || [];
3023
parent.children.push(node);
31-
}
32-
33-
// Fill root tree node
34-
if (parentKey === rootPId || (!parent && rootPId === null)) {
35-
rootNodeList.push(node);
24+
} else if (parentKey === rootPId || rootPId === null) {
25+
rootNodes.push(node);
3626
}
3727
});
3828

39-
return rootNodeList;
29+
return rootNodes;
4030
}
4131

4232
/**
43-
* Convert `treeData` or `children` into formatted `treeData`.
44-
* Will not re-calculate if `treeData` or `children` not change.
33+
* `treeData` `children` 转换为格式化的 `treeData`
34+
* 如果 `treeData` `children` 没有变化,则不会重新计算。
4535
*/
4636
export default function useTreeData(
4737
treeData: DataNode[],
@@ -50,14 +40,16 @@ export default function useTreeData(
5040
): DefaultOptionType[] {
5141
return React.useMemo(() => {
5242
if (treeData) {
53-
return simpleMode
54-
? parseSimpleTreeData(treeData, {
55-
id: 'id',
56-
pId: 'pId',
57-
rootPId: null,
58-
...(simpleMode !== true ? simpleMode : {}),
59-
})
60-
: treeData;
43+
if (simpleMode) {
44+
const config: SimpleModeConfig = {
45+
id: 'id',
46+
pId: 'pId',
47+
rootPId: null,
48+
...(typeof simpleMode === 'object' ? simpleMode : {}),
49+
};
50+
return buildTreeStructure(treeData, config);
51+
}
52+
return treeData;
6153
}
6254

6355
return convertChildrenToData(children);

src/utils/valueUtil.ts

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,41 @@
11
import type { DataNode, FieldNames, SafeKey } from '../interface';
22
import type { DefaultOptionType, InternalFieldName } from '../TreeSelect';
33

4-
export function toArray<T>(value: T | T[]): T[] {
5-
if (Array.isArray(value)) {
6-
return value;
7-
}
8-
return value !== undefined ? [value] : [];
9-
}
10-
11-
export function fillFieldNames(fieldNames?: FieldNames) {
12-
const { label, value, children } = fieldNames || {};
13-
14-
const mergedValue = value || 'value';
4+
export const toArray = <T>(value: T | T[]): T[] =>
5+
Array.isArray(value) ? value : value !== undefined ? [value] : [];
156

7+
export const fillFieldNames = (fieldNames?: FieldNames) => {
8+
const { label, value, children } = fieldNames || {};
169
return {
1710
_title: label ? [label] : ['title', 'label'],
18-
value: mergedValue,
19-
key: mergedValue,
11+
value: value || 'value',
12+
key: value || 'value',
2013
children: children || 'children',
2114
};
22-
}
15+
};
2316

24-
export function isCheckDisabled(node: DataNode) {
25-
return !node || node.disabled || node.disableCheckbox || node.checkable === false;
26-
}
17+
export const isCheckDisabled = (node: DataNode): boolean =>
18+
!node || node.disabled || node.disableCheckbox || node.checkable === false;
2719

28-
/** Loop fetch all the keys exist in the tree */
29-
export function getAllKeys(treeData: DefaultOptionType[], fieldNames: InternalFieldName) {
20+
export const getAllKeys = (
21+
treeData: DefaultOptionType[],
22+
fieldNames: InternalFieldName,
23+
): SafeKey[] => {
3024
const keys: SafeKey[] = [];
3125

32-
function dig(list: DefaultOptionType[]) {
26+
const dig = (list: DefaultOptionType[]): void => {
3327
list.forEach(item => {
3428
const children = item[fieldNames.children];
3529
if (children) {
3630
keys.push(item[fieldNames.value]);
3731
dig(children);
3832
}
3933
});
40-
}
34+
};
4135

4236
dig(treeData);
4337

4438
return keys;
45-
}
39+
};
4640

47-
export function isNil(val: any) {
48-
return val === null || val === undefined;
49-
}
41+
export const isNil = (val: any): boolean => val === null || val === undefined;

0 commit comments

Comments
 (0)