Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 数据域组件扩充 trackExpression 属性用于显式的设置跟踪上层数据变化 Close: #7152 #7169

Merged
merged 7 commits into from
Jun 16, 2023
71 changes: 70 additions & 1 deletion docs/zh-CN/concepts/datascope-and-datachain.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,31 @@ page

> **注意:** 当前例子中,对数据域中数据的获取使用的是 **\${xxx}** 模板语法,但是在不同的组件配置项中,获取数据的语法会有差异,我们会在后续的[模板](./template)和[表达式章节](./expression)中一一介绍。

### 具备数据域的组件

- App
- Page
- Cards
- Chart
- CRUD
- CRUD2
- Dialog
- Drawer
- List
- Page
- PaginationWrapper
- Service
- Wizard
- Combo
- InputArray
- Table
- Table2

有个特殊情况是 CRUD 中 filter,实际上是个 form,所以 CRUD 中有两层数据域,第一层是 CRUD 本身,同时查询条件表单中也有一层数据域。

### 常见误解

需要注意,只有少数几个容器组件会创建新的数据域,除了最顶层的 Page,还有 CRUD、Dialog、IFrame、Form、Service 等
需要注意,只有少数几个容器组件会创建新的数据域,具体查看[具备数据域的组件](#具备数据域的组件)列表

常见的错误写法是给容器组件加 data 属性,比如:

Expand Down Expand Up @@ -377,6 +399,53 @@ page

> 具有类似特征的组件还有`Formula`等

## 更新数据链

通常顶层数据域数据更新,孩子中具备数据域的组件都会更新,如果不更新会拿不到最新的值。从功能来看这个更新代价其实是很大的,有性能损耗,比如如果我在顶层更新了个变量 `name`,所有的孩子都会重新刷新一遍。
目前 amis 中,具备数据域的组件,默认会检测两层节点的数据是否发生变化(上层数据域和上上层数据域),来决定当前层的数据要不要更新。存在两个问题:

1. 当前组件也许并不关心上层数据是否变化,没必要进行这些刷新操作
2. 当前组件关系上上层的数据变化,但是在此拿不到最新的。(比如:放在 service 中的 crud,crud 中 filter 用了 service 的接口返回数据,但是拿不到最新的)

amis 从 3.2.0 版本开始针对[具备数据域的组件](#具备数据域的组件)新增了 `trackExpression` 属性,用来主动配置当前组件需要关心的上层数据。

针对以上问题,则可以通过这样配置来解决

1. `trackExpression` 配置成 `"none"` 也就是说不追踪任何数据。
2. `trackExpression` 配置成 `"${xxxVariable}"` 这样 xxxVariable 变化了更新当前组件的数据链。

关于 `trackExpression` 的语法,请查看表达式篇章,可以监听多个变量比如: `"${xxx1},${xxx2}"`,还可以写表单时如 `"${ xxx ? xxx : yyy}"`。

amis 内部是通过运算这个表达式的结果来判断。所以表达式中千万不要用随机函数,或者用当前时间等,否则每次都会更新数据链。另外如果变量是数组,或者对象,会转成统一的字符串 `[object Array]` 或者 `[object Object]` 这个其实会影响检测的,所以建议转成 json 字符串如。 `${xxxObject | json}`。还有就是既然是监控上层数据,表达式中不要写当前层数据变量,是取不到的。

```schema
{
"data": {
"name": "amis"
},
"type": "page",
"body": [
{ "label": "请修改输入框", "type": "input-text", "name": "name"},
{
"type": "switch",
"label": "同步更新",
"name": "syncSwitch"
},
{
"type": "crud",
"filter": {
"trackExpression": "${syncSwitch ? name : ''}",
"body": [


"my name is ${name}"
]
}
}
]
}
```

## URL 参数

url 中的参数会进入顶层数据域,比如下面的例子,可以点击[这里](./datascope-and-datachain?word=myquery#url-参数)看效果。
Expand Down
3 changes: 2 additions & 1 deletion packages/amis-core/src/SchemaRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ export const RENDERER_TRANSMISSION_OMIT_PROPS = [
'id',
'inputOnly',
'label',
'renderLabel'
'renderLabel',
'trackExpression'
];

const componentCache: SimpleMap = new SimpleMap();
Expand Down
36 changes: 21 additions & 15 deletions packages/amis-core/src/WithStore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
syncDataFromSuper,
isSuperDataModified
} from './utils/helper';
import {dataMapping} from './utils/tpl-builtin';
import {dataMapping, tokenize} from './utils/tpl-builtin';
import {RootStoreContext} from './WithRootStore';

export function HocStoreFactory(renderer: {
Expand Down Expand Up @@ -191,13 +191,16 @@ export function HocStoreFactory(renderer: {
if (
shouldSync === true ||
prevProps.defaultData !== props.defaultData ||
isObjectShallowModified(prevProps.data, props.data) ||
//
// 特殊处理 CRUD。
// CRUD 中 toolbar 里面的 data 是空对象,但是 __super 会不一样
(props.data &&
prevProps.data &&
props.data.__super !== prevProps.data.__super)
(props.trackExpression
? tokenize(props.trackExpression, props.data!) !==
tokenize(props.trackExpression, prevProps.data!)
: isObjectShallowModified(prevProps.data, props.data) ||
//
// 特殊处理 CRUD。
// CRUD 中 toolbar 里面的 data 是空对象,但是 __super 会不一样
(props.data &&
prevProps.data &&
props.data.__super !== prevProps.data.__super))
) {
store.initData(
extendObject(props.data, {
Expand All @@ -209,9 +212,12 @@ export function HocStoreFactory(renderer: {
}
} else if (
shouldSync === true ||
isObjectShallowModified(prevProps.data, props.data) ||
(props.syncSuperStore !== false &&
isSuperDataModified(props.data, prevProps.data, store))
(props.trackExpression
? tokenize(props.trackExpression, props.data!) !==
tokenize(props.trackExpression, prevProps.data!)
: isObjectShallowModified(prevProps.data, props.data) ||
(props.syncSuperStore !== false &&
isSuperDataModified(props.data, prevProps.data, store)))
) {
if (props.store && props.store.data === props.data) {
store.initData(
Expand Down Expand Up @@ -246,9 +252,8 @@ export function HocStoreFactory(renderer: {
store.initData(createObject(props.scope, props.data));
}
} else if (
(shouldSync === true ||
!props.store ||
props.data !== props.store.data) &&
!props.trackExpression &&
(!props.store || props.data !== props.store.data) &&
props.data &&
props.data.__super
) {
Expand All @@ -273,9 +278,10 @@ export function HocStoreFactory(renderer: {
}
// nextProps.data.__super !== props.data.__super) &&
} else if (
!props.trackExpression &&
props.scope &&
props.data === props.store!.data &&
(shouldSync === true || prevProps.data !== props.data)
prevProps.data !== props.data
) {
// 只有父级数据变动的时候才应该进来,
// 目前看来这个 case 很少有情况下能进来
Expand Down
2 changes: 1 addition & 1 deletion packages/amis-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export interface BaseApiObject {

/**
* 当开启自动刷新的时候,默认是 api 的 url 来自动跟踪变量变化的。
* 如果你希望监控 url 外的变量,请配置 traceExpression
* 如果你希望监控 url 外的变量,请配置 trackExpression
*/
trackExpression?: string;

Expand Down
2 changes: 1 addition & 1 deletion packages/amis/src/Schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ export interface SchemaApiObject {

/**
* 当开启自动刷新的时候,默认是 api 的 url 来自动跟踪变量变化的。
* 如果你希望监控 url 外的变量,请配置 traceExpression
* 如果你希望监控 url 外的变量,请配置 trackExpression
*/
trackExpression?: string;

Expand Down