Skip to content

Commit 247a1da

Browse files
committed
性能优化
1 parent e967277 commit 247a1da

1 file changed

Lines changed: 63 additions & 15 deletions

File tree

src/utils/reactNodeUtil.tsx

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,86 @@
11
import React, { cloneElement, isValidElement } from 'react';
22

3-
const stripProps = (props: Record<string, any>) => {
4-
const result: Record<string, any> = {};
3+
// 预定义需要剥离的属性集合,提高查找性能
4+
const STRIP_PROPS = new Set(['id', 'ref', 'onFocus', 'onBlur', 'tabIndex']);
5+
6+
// 使用 WeakMap 缓存已处理的 props,避免重复计算
7+
const propsCache = new WeakMap<Record<string, unknown>, Record<string, unknown>>();
8+
9+
const stripProps = (props: Record<string, unknown>) => {
10+
// 检查缓存
11+
const cached = propsCache.get(props);
12+
if (cached) {
13+
return cached;
14+
}
15+
16+
let hasChanges = false;
17+
const result: Record<string, unknown> = {};
18+
519
for (const key in props) {
6-
// strip data-*、id、ref, onFocus、onBlur
7-
if (
8-
key === 'id' ||
9-
key === 'ref' ||
10-
key === 'onFocus' ||
11-
key === 'onBlur' ||
12-
key === 'tabIndex' ||
13-
key.startsWith('data-')
14-
)
20+
// 使用 Set 进行 O(1) 查找,优化 data-* 属性检查
21+
if (STRIP_PROPS.has(key) || key.startsWith('data-')) {
22+
hasChanges = true;
1523
continue;
24+
}
1625
result[key] = props[key];
1726
}
18-
return result;
27+
28+
// 如果没有需要剥离的属性,直接返回原对象
29+
const finalResult = hasChanges ? result : props;
30+
31+
// 缓存结果
32+
propsCache.set(props, finalResult);
33+
34+
return finalResult;
1935
};
2036

37+
// 使用 WeakMap 缓存已处理的节点,避免重复处理
38+
const nodeCache = new WeakMap<React.ReactElement, React.ReactNode>();
39+
2140
/**
2241
* Recursively clone ReactNode and remove data-*, id, ref, onFocus, onBlur props
2342
* to avoid potential issues with nested elements in table cells.
43+
*
44+
* 优化特性:
45+
* 1. 缓存机制避免重复处理相同节点
46+
* 2. 提前退出条件减少不必要的递归
47+
* 3. 浅层优化:如果props没有变化,直接返回原节点
2448
*/
2549
const sanitizeCloneElement = (node: React.ReactNode): React.ReactNode => {
2650
if (!isValidElement(node)) {
2751
return node;
2852
}
29-
const cleanedProps = stripProps(node.props);
53+
54+
// 检查缓存
55+
const cached = nodeCache.get(node);
56+
if (cached) {
57+
return cached;
58+
}
59+
60+
const cleanedProps = stripProps(node.props as Record<string, unknown>);
61+
62+
// 如果props没有变化且没有children需要处理,直接返回原节点
63+
if (cleanedProps === node.props && !cleanedProps.children) {
64+
nodeCache.set(node, node);
65+
return node;
66+
}
67+
68+
let processedChildren = cleanedProps.children;
3069
if (cleanedProps.children) {
31-
cleanedProps.children = React.Children.map(cleanedProps.children, child =>
70+
processedChildren = React.Children.map(cleanedProps.children as React.ReactNode, child =>
3271
sanitizeCloneElement(child),
3372
);
3473
}
35-
return cloneElement(node, cleanedProps);
74+
75+
const result = cloneElement(node, {
76+
...cleanedProps,
77+
children: processedChildren,
78+
} as React.Attributes);
79+
80+
// 缓存结果
81+
nodeCache.set(node, result);
82+
83+
return result;
3684
};
3785

3886
export { sanitizeCloneElement };

0 commit comments

Comments
 (0)