fix: 修复性能优化后在需要用到父级数据的时候没有及时更新的问题 Close: #8188 (#8193)

This commit is contained in:
liaoxuezhi 2023-09-21 19:47:44 +08:00 committed by GitHub
parent 7d7fe0d14b
commit 7d7c8055d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 121 additions and 5 deletions

View File

@ -20,7 +20,8 @@ import {autobindMethod} from './autobind';
import { import {
isPureVariable, isPureVariable,
resolveVariable, resolveVariable,
resolveVariableAndFilter resolveVariableAndFilter,
tokenize
} from './tpl-builtin'; } from './tpl-builtin';
import { import {
cloneObject, cloneObject,
@ -1896,13 +1897,17 @@ export function hashCode(s: string): number {
*/ */
export function JSONTraverse( export function JSONTraverse(
json: any, json: any,
mapper: (value: any, key: string | number, host: Object) => any mapper: (value: any, key: string | number, host: Object) => any,
maxDeep: number = Number.MAX_VALUE
) { ) {
if (maxDeep <= 0) {
return;
}
Object.keys(json).forEach(key => { Object.keys(json).forEach(key => {
const value: any = json[key]; const value: any = json[key];
if (!isObservable(value)) { if (!isObservable(value)) {
if (isPlainObject(value) || Array.isArray(value)) { if (isPlainObject(value) || Array.isArray(value)) {
JSONTraverse(value, mapper); JSONTraverse(value, mapper, maxDeep - 1);
} else { } else {
mapper(value, key, json); mapper(value, key, json);
} }
@ -2073,3 +2078,99 @@ export function differenceFromAll<T>(
differenceFromAllCache.res = res; differenceFromAllCache.res = res;
return res; return res;
} }
/**
* schema trackExpression
*
* @param schema
* @returns
*/
export function buildTrackExpression(schema: any) {
if (!isPlainObject(schema) && !Array.isArray(schema)) {
return '';
}
const trackExpressions: Array<string> = [];
JSONTraverse(
schema,
(value, key: string) => {
if (typeof value !== 'string') {
return;
}
if (key === 'name') {
trackExpressions.push(isPureVariable(value) ? value : `\${${value}}`);
} else if (key === 'source') {
trackExpressions.push(value);
} else if (
key.endsWith('On') ||
key === 'condition' ||
key === 'trackExpression'
) {
trackExpressions.push(
value.startsWith('${') ? value : `<script>${value}</script>`
);
} else if (value.includes('$')) {
trackExpressions.push(value);
}
},
10 // 最多遍历 10 层
);
return trackExpressions.join('|');
}
export function evalTrackExpression(
expression: string,
data: Record<string, any>
) {
if (typeof expression !== 'string') {
return '';
}
const parts: Array<{
type: 'text' | 'script';
value: string;
}> = [];
while (true) {
// 这个是自动提取的时候才会用到,用户配置不要用到这个语法
const idx = expression.indexOf('<script>');
if (idx === -1) {
break;
}
const endIdx = expression.indexOf('</script>');
if (endIdx === -1) {
throw new Error(
'Invalid trackExpression miss end script token `</script>`'
);
}
if (idx) {
parts.push({
type: 'text',
value: expression.substring(0, idx)
});
}
parts.push({
type: 'script',
value: expression.substring(idx + 8, endIdx)
});
expression = expression.substring(endIdx + 9);
}
expression &&
parts.push({
type: 'text',
value: expression
});
return parts
.map(item => {
if (item.type === 'text') {
return tokenize(item.value, data);
}
return evalExpression(item.value, data);
})
.join('');
}

View File

@ -5,7 +5,9 @@ import {
PlainObject, PlainObject,
SchemaNode, SchemaNode,
ThemeProps, ThemeProps,
resolveVariable resolveVariable,
buildTrackExpression,
evalTrackExpression
} from 'amis-core'; } from 'amis-core';
import {BadgeObject, Checkbox, Icon} from 'amis-ui'; import {BadgeObject, Checkbox, Icon} from 'amis-ui';
import React from 'react'; import React from 'react';
@ -168,7 +170,20 @@ export default function Cell({
} }
return [prefix, affix, addtionalClassName]; return [prefix, affix, addtionalClassName];
}, [item.expandable, item.expanded]); }, [item.expandable, item.expanded]);
const data = React.useMemo(() => item.locals, [JSON.stringify(item.locals)]);
// 根据条件缓存 data避免孩子重复渲染
const hasCustomTrackExpression =
typeof column.pristine.trackExpression !== 'undefined';
const trackExpression = hasCustomTrackExpression
? column.pristine.trackExpression
: React.useMemo(() => buildTrackExpression(column.pristine), []);
const data = React.useMemo(
() => item.locals,
[
hasCustomTrackExpression ? '' : JSON.stringify(item.locals),
evalTrackExpression(trackExpression, item.locals)
]
);
const finalCanAccessSuperData = const finalCanAccessSuperData =
column.pristine.canAccessSuperData ?? canAccessSuperData; column.pristine.canAccessSuperData ?? canAccessSuperData;