Skip to content

Commit 666f61c

Browse files
committed
chore: add slotMode
1 parent d7b2b66 commit 666f61c

File tree

6 files changed

+169
-46
lines changed

6 files changed

+169
-46
lines changed

content/docs/core/field/basicConfig.cn.mdx

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,69 @@ const account = defineField({
9898
})
9999
```
100100

101+
## 插槽模式
102+
- 插槽模式是指字段的子字段的在组件中的渲染方式。默认情况下,子字段会作为组件的子元素渲染在组件中。当字段的 `slotMode``true` 时,表示字段的子字段会作为组件的 `props` 传递给组件,让组件自己决定如何渲染子字段。
103+
- `slotName`: 插槽的名称,用于在表单中标识插槽。默认为字段的 `id`
104+
- `slotMode`: 插槽的模式,用于控制插槽的渲染方式。
105+
106+
```ts
107+
const firstName = defineField({
108+
id: "firstName",
109+
component: Input,
110+
props: {
111+
label: "firstName",
112+
prefix: "👤",
113+
required: true,
114+
},
115+
});
116+
117+
const lastName = defineField({
118+
id: "lastName",
119+
component: Input,
120+
props: {
121+
label: "lastName",
122+
prefix: "👤",
123+
required: true,
124+
},
125+
});
126+
127+
const usernameLayout = defineVoidField({
128+
id: "usernameLayout",
129+
component: Flex,
130+
slotMode: true,
131+
hidden: (handler) => {
132+
return handler.queryState(age)?.value > 18;
133+
},
134+
properties: [firstName, lastName],
135+
props: {
136+
vertical: false,
137+
}
138+
});
139+
140+
function Flex(props: {
141+
firstName?: RectNode;
142+
lastName?: RectNode;
143+
vertical?: boolean;
144+
}) {
145+
return (
146+
<div
147+
style={{
148+
display: "flex",
149+
flexDirection: props.vertical ? "column" : "row",
150+
alignItems: "center",
151+
gap: 8,
152+
}}
153+
>
154+
{props.firstName}
155+
{props.lastName}
156+
</div>
157+
);
158+
}
159+
160+
```
161+
162+
163+
101164
## hidden
102165

103166
- `hidden` 是一个 `Decision` 对象,表示字段是否禁用。`hidden` 也可以是一个函数。函数的参数是,仅具备读操作的 `handler` ,返回值是一个布尔值。默认值是 false。

content/docs/core/field/basicConfig.mdx

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,67 @@ const account = defineField({
100100
})
101101
```
102102

103+
104+
## slotMode
105+
- slot mode refers to the way a subfield of a field is rendered in a component by default subfields are rendered in the component as child elements of the component when the `slotMode` of a field is `true` the subfields representing the field are passed to the component as the component's `props` allowing the component to decide how to render the subfields themselves.
106+
- `slotName`: the name of the slot used to identify the slot in the form default is field `id`.
107+
- `slotMode`: slot mode used to control the rendering method of slots.
108+
109+
```ts
110+
const firstName = defineField({
111+
id: "firstName",
112+
component: Input,
113+
props: {
114+
label: "firstName",
115+
prefix: "👤",
116+
required: true,
117+
},
118+
});
119+
120+
const lastName = defineField({
121+
id: "lastName",
122+
component: Input,
123+
props: {
124+
label: "lastName",
125+
prefix: "👤",
126+
required: true,
127+
},
128+
});
129+
130+
const usernameLayout = defineVoidField({
131+
id: "usernameLayout",
132+
component: Flex,
133+
slotMode: true,
134+
hidden: (handler) => {
135+
return handler.queryState(age)?.value > 18;
136+
},
137+
properties: [firstName, lastName],
138+
props: {
139+
vertical: false,
140+
}
141+
});
142+
143+
function Flex(props: {
144+
firstName?: RectNode;
145+
lastName?: RectNode;
146+
vertical?: boolean;
147+
}) {
148+
return (
149+
<div
150+
style={{
151+
display: "flex",
152+
flexDirection: props.vertical ? "column" : "row",
153+
alignItems: "center",
154+
gap: 8,
155+
}}
156+
>
157+
{props.firstName}
158+
{props.lastName}
159+
</div>
160+
);
161+
}
162+
```
163+
103164
## hidden
104165

105166
- `hidden` is a `Decision` object that indicates whether the field is hidden. `hidden` can also be a function. The function's parameters are a `handler` with read-only operations, and the return value is a boolean. The default value is false.

content/docs/core/relation/defineReaction.cn.mdx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const reaction = defineReaction({
3939
|------|------|--------|------|
4040
| `immediate` | `boolean` | `false` | 是否立即执行(初始化时就触发) |
4141
| `once` | `boolean` | `false` | 是否只执行一次 |
42-
| `dirtyIgnore` | `boolean` | `false` | 是否忽略脏值更新(跳过多次执行的优化) |
42+
| `dirtyIgnore` | `boolean` | `true` | 是否忽略脏值更新(跳过多次执行的优化) |
4343

4444
### 更新函数
4545

@@ -167,25 +167,25 @@ const initReaction = defineReaction({
167167

168168
### 脏值检查控制
169169

170-
默认情况下,为了优化性能,系统会跳过相同值的重复更新。使用 `dirtyIgnore` 可以跳过这个优化:
170+
默认情况下,为了优化性能,系统会跳过重复更新。使用 `dirtyIgnore` 可以跳过这个优化:
171171

172172
```ts
173173
const cacheReaction = defineReaction({
174174
field: cache,
175175
dependencies: [input],
176176
update: (handler, [inputValue]) => {
177-
// 设置 dirtyIgnore: true 后,即使输入值相同,也会执行更新
177+
// 设置 dirtyIgnore: true 后,多次触发时,只有最后一次生效
178178
handler.setState('value', `cached_${inputValue}_${Date.now()}`)
179179
},
180180
options: {
181-
dirtyIgnore: true // 忽略脏值检查,即使值相同也执行更新
181+
dirtyIgnore: true // 多次触发时,只有最后一次生效
182182
}
183183
})
184184
```
185185

186186
**工作原理:**
187-
- `dirtyIgnore: false`(默认):如果依赖字段的值没有变化,跳过更新函数的执行
188-
- `dirtyIgnore: true`:无论依赖字段的值是否变化,都执行更新函数
187+
- `dirtyIgnore: true`(默认):当多次执行时,会跳过前面的执行,只有最后一次执行会生效
188+
- `dirtyIgnore: false`:当多次执行时,每次都会执行更新函数
189189

190190
### 取消异步操作
191191

@@ -225,7 +225,7 @@ const searchReaction = defineReaction({
225225
## 注意事项
226226

227227
1. **循环依赖**:系统支持循环依赖,但请确保不要在更新函数中修改 `value` 属性,否则会造成无限循环
228-
2. **性能考虑**:默认的脏值检查有助于性能优化,除非必要(如需要基于时间戳等动态值更新),不建议设置 `dirtyIgnore: true`
228+
2. **性能考虑**:默认的脏值检查有助于性能优化,除非必要(如需要基于时间戳等动态值更新),不建议设置 `dirtyIgnore: false`
229229
3. **异步处理**:对于异步更新,务必处理 AbortSignal 以避免内存泄漏和竞态条件
230230
4. **多对多联动**:尽量避免多对多的联动模式,优先使用多对一的方式
231231

content/docs/core/relation/defineReaction.mdx

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
---
2-
title: Basic Reactions
3-
description: Define field dependencies and implement reactive data flow
2+
title: Basic Reaction
3+
description: Define field reaction relationships to implement reactive data flow
44
---
55

66
## Overview
77

8-
`defineReaction` is used to define reactive relationships between fields. When dependency fields change, it automatically triggers update logic for target fields.
8+
`defineReaction` is used to define reaction relationships between fields. When dependency fields change, it automatically triggers the update logic of target fields.
99

1010
## Basic Usage
1111

@@ -14,7 +14,7 @@ import { defineReaction } from '@signals-form/core'
1414

1515
const reaction = defineReaction({
1616
field: targetField, // Target field
17-
dependencies: [sourceField], // Array of dependency fields
17+
dependencies: [sourceField], // Dependency field array
1818
update: (handler, values) => {
1919
// Update logic
2020
handler.setState('value', values[0])
@@ -28,9 +28,9 @@ const reaction = defineReaction({
2828

2929
| Parameter | Type | Required | Description |
3030
|-----------|------|----------|-------------|
31-
| `field` | `Field\|string` || Target field (the field being updated) |
32-
| `dependencies` | `(Field\|string)[]` || Array of dependency fields (fields that trigger updates) |
33-
| `update` | `UpdateFunction` || Update function for reactive behavior |
31+
| `field` | `Field\|string` || Target field (field to be reacted) |
32+
| `dependencies` | `(Field\|string)[]` || Dependency field array (fields that trigger reactions) |
33+
| `update` | `UpdateFunction` || Reaction update function |
3434
| `options` | `Options` || Configuration options |
3535

3636
### Options Configuration
@@ -39,21 +39,21 @@ const reaction = defineReaction({
3939
|--------|------|---------|-------------|
4040
| `immediate` | `boolean` | `false` | Whether to execute immediately (trigger on initialization) |
4141
| `once` | `boolean` | `false` | Whether to execute only once |
42-
| `dirtyIgnore` | `boolean` | `false` | Whether to ignore dirty value checks (skip duplicate execution optimization) |
42+
| `dirtyIgnore` | `boolean` | `true` | Whether to ignore dirty value updates (optimization to skip multiple executions) |
4343

4444
### Update Function
4545

4646
```ts
4747
type UpdateFunction = (
48-
handler: FieldHandler, // Handler for the target field
49-
values: any[], // Array of dependency field values
50-
abortSignal: AbortSignal // Cancellation signal
48+
handler: FieldHandler, // Operation handle for target field
49+
values: any[], // Value array of dependency fields
50+
abortSignal: AbortSignal // Abort signal
5151
) => void | Promise<any>
5252
```
5353
5454
### Automatic Dependency Collection
5555
56-
`defineReaction` supports functional calls with automatic dependency collection:
56+
`defineReaction` supports functional calls with automatic dependency collection and execution:
5757
5858
```ts
5959
const reaction = defineReaction((handler) => {
@@ -86,7 +86,7 @@ const usernameReaction = defineReaction({
8686

8787
### Async Reaction
8888

89-
```ts title="Fetch districts based on city"
89+
```ts title="Get district list based on city"
9090
const districtReaction = defineReaction({
9191
field: district,
9292
dependencies: [city],
@@ -122,9 +122,9 @@ const totalReaction = defineReaction({
122122
})
123123
```
124124

125-
### Many-to-Many Reactions
125+
### Many-to-Many Reaction
126126

127-
Supports multiple fields updating multiple target fields simultaneously, but use with caution - prefer many-to-one patterns:
127+
Supports multiple fields updating multiple target fields simultaneously, but use with caution - prefer many-to-one approach:
128128

129129
```ts title="Many-to-many dependency updates"
130130
const multiTargetReaction = defineReaction({
@@ -143,7 +143,7 @@ const multiTargetReaction = defineReaction({
143143
})
144144
```
145145

146-
> ⚠️ **Warning**: Minimize many-to-many scenarios. Prefer many-to-one patterns for better maintainability and debugging.
146+
> ⚠️ **Note**: Try to minimize many-to-many usage scenarios. Prefer many-to-one approaches for reaction logic as they are easier to maintain and debug.
147147
148148
### One-time Reaction
149149

@@ -167,29 +167,29 @@ const initReaction = defineReaction({
167167

168168
### Dirty Value Check Control
169169

170-
By default, the system skips duplicate updates with identical values for performance optimization. Use `dirtyIgnore` to bypass this optimization:
170+
By default, the system skips redundant updates for performance optimization. Use `dirtyIgnore` to bypass this optimization:
171171

172172
```ts
173173
const cacheReaction = defineReaction({
174174
field: cache,
175175
dependencies: [input],
176176
update: (handler, [inputValue]) => {
177-
// With dirtyIgnore: true, update executes even with identical input values
177+
// With dirtyIgnore: true, when triggered multiple times, only the last execution takes effect
178178
handler.setState('value', `cached_${inputValue}_${Date.now()}`)
179179
},
180180
options: {
181-
dirtyIgnore: true // Ignore dirty checks, execute update even with identical values
181+
dirtyIgnore: true // When triggered multiple times, only the last execution takes effect
182182
}
183183
})
184184
```
185185

186186
**How it works:**
187-
- `dirtyIgnore: false` (default): Skip update function execution if dependency field values haven't changed
188-
- `dirtyIgnore: true`: Execute update function regardless of whether dependency field values have changed
187+
- `dirtyIgnore: true` (default): When executed multiple times, skips previous executions and only the last one takes effect
188+
- `dirtyIgnore: false`: When executed multiple times, each execution runs the update function
189189

190190
### Canceling Async Operations
191191

192-
For async updates, the system automatically provides AbortSignal to cancel outdated requests:
192+
For async update operations, the system automatically provides AbortSignal to cancel outdated requests:
193193

194194
```ts
195195
const searchReaction = defineReaction({
@@ -201,9 +201,9 @@ const searchReaction = defineReaction({
201201
return
202202
}
203203

204-
// Listen for cancellation signal
204+
// Listen for abort signal
205205
abortSignal?.addEventListener('abort', () => {
206-
console.log('Search request was cancelled')
206+
console.log('Search request cancelled')
207207
})
208208

209209
try {
@@ -224,10 +224,10 @@ const searchReaction = defineReaction({
224224

225225
## Important Notes
226226

227-
1. **Circular Dependencies**: The system supports circular dependencies, but ensure you don't modify the `value` property in update functions to avoid infinite loops
228-
2. **Performance Considerations**: Default dirty value checking helps optimize performance. Avoid setting `dirtyIgnore: true` unless necessary (e.g., updates based on timestamps or other dynamic values)
229-
3. **Async Handling**: For async updates, always handle AbortSignal to prevent memory leaks and race conditions
230-
4. **Many-to-Many Reactions**: Avoid many-to-many reactive patterns when possible; prefer many-to-one approaches
227+
1. **Circular Dependencies**: The system supports circular dependencies, but ensure you don't modify the `value` property in update functions, as this will cause infinite loops
228+
2. **Performance Considerations**: Default dirty value checking helps with performance optimization. Unless necessary (e.g., updates based on timestamps or dynamic values), avoid setting `dirtyIgnore: false`
229+
3. **Async Handling**: For async updates, always handle AbortSignal to avoid memory leaks and race conditions
230+
4. **Many-to-Many Reactions**: Avoid many-to-many reaction patterns when possible. Prefer many-to-one approaches
231231

232232
## Type Definitions
233233

@@ -240,13 +240,13 @@ export interface Reaction<
240240
> {
241241
/** Target field */
242242
field: Dependency<T, P, E>;
243-
/** Array of dependency fields */
243+
/** Dependency field array */
244244
dependencies: [...D];
245245
/**
246246
* Update function called when dependencies change
247-
* @param handler - Field operation handler
248-
* @param depValues - Array of dependency field values
249-
* @param signal - Cancellation signal
247+
* @param handler - Field operation handle
248+
* @param depValues - Value array of dependency fields
249+
* @param signal - Abort signal
250250
*/
251251
update: (
252252
handler: FieldHandler<T, P>,
@@ -258,10 +258,10 @@ export interface Reaction<
258258
once?: boolean;
259259
/** Whether to trigger immediately */
260260
immediate?: boolean;
261-
/** Whether to ignore dirty value checks, skip duplicate value updates, defaults to false */
261+
/** Whether to ignore dirty value checks, skip multiple execution value updates, default is true */
262262
dirtyIgnore?: boolean;
263263
};
264264
}
265265
```
266266

267-
Basic reactions are the fundamental reactive pattern, suitable for most scenarios. For more advanced control capabilities, consider using
267+
Basic reactions are the most fundamental reaction type, suitable for most scenarios. For more advanced control capabilities, consider using `defineRelation` controlled reactions.

content/docs/core/relation/defineRelation.cn.mdx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const relation = defineRelation({
5353
|------|------|--------|------|
5454
| `isImmediate` | `boolean` | `false` | 是否立即执行(初始化时就触发) |
5555
| `once` | `boolean` | `false` | 是否只执行一次 |
56-
| `dirtyIgnore` | `boolean` | `false` | 是否忽略脏值更新(总是执行更新) |
56+
| `dirtyIgnore` | `boolean` | `true` | 是否忽略脏值更新(总是执行更新) |
5757

5858
### 更新函数
5959

@@ -340,7 +340,7 @@ export interface Relation<
340340
once?: boolean;
341341
/** If true, the reaction will be triggered immediately */
342342
immediate?: boolean;
343-
/** If true, the reaction will be allowed to skip updates multiple times, default is false */
343+
/** If true, the reaction will be allowed to skip updates multiple times, default is true */
344344
dirtyIgnore?: boolean;
345345
// support for debounce and throttle ?
346346
};
@@ -352,6 +352,5 @@ export interface Relation<
352352
1. **合理设置依赖** - 只依赖真正需要的字段
353353
2. **使用 AbortSignal** - 及时取消无效的异步操作
354354
3. **避免循环依赖** - 检查字段依赖关系图
355-
4. **适当使用 dirtyIgnore** - 在需要时忽略脏值检查
356355

357356
受控联动是 Signals Form 的核心特性,让复杂的字段关系变得简单可控!✨

0 commit comments

Comments
 (0)