dehub
Version:
Data&Event MessageHub.
354 lines (273 loc) • 8.96 kB
Markdown
# DEHub
DEHub is a message-driven library for JavaScript-based clients. It unifies the handling of events and data in all clients by using messages for subscription and processing. This allows all components and business processes in a page to handle business logic in a subscribable manner, and enables access to all registered components through context.
## Key Features
- Component Registration and Management
- Supports batch component registration
- Supports parent-child component relationships
- Supports asynchronous component loading
- Supports component state management and updates
- Supports component lifecycle events
- Data Management
- Supports multiple data loading modes (localDB, custom, none)
- Supports data singleton maintenance
- Supports virtual fields
- Supports data reset and cleanup
- Supports data cache management
- Supports high-performance handling of large datasets
- Event System
- Supports event subscription and processing
- Supports event pre-processing and post-processing
- Supports event context access
## Quick Start
### Component Registration
```typescript
// Create and register a basic component
const tag = new Tag({ id: 'cmp1' });
const comp1 = new DEComp<any>(tag);
await regComponent(comp1);
// Wait for component to be ready
await comp1.waitReady();
// Update component state
await comp1.update({ a: 1, b: 'abc' });
```
### Component State Management
```typescript
// Listen for component state changes
when({
id: 'cmp1',
event: EventNames.StateChanging,
stage: EventStage.PostOperation
}, (context: EventContext) => {
const comp = context.sender as DEComp;
// Handle state changes
});
// Update component state
await comp1.update({ a: 2 });
```
### Data Management
```typescript
// Create data tag
const IdTag = (entity: string, id: string): Tag => {
return new Tag({ entity, id });
};
// Get data object
const user1Tag = IdTag('user.demo@org0', 'user1');
const user1Data = await fetchData(user1Tag, {
loadingMode: 'custom',
default: { name: 'Default' }
});
// Wait for data to load
await user1Data.until(ObjectStatus.Ready);
// Modify data
await user1Data.set("name", "John");
await user1Data.set("age", 25);
// Submit data
await user1Data.submit();
```
### Data Loading Modes
```typescript
// LocalDB mode - Load from local database
const localData = await fetchData({ id: 'localData1' }, {
loadingMode: 'localDB',
default: { a: 1 }
});
// Custom mode - Custom loading logic
const customData = await fetchData({ id: 'customData1' }, {
loadingMode: 'custom'
});
// None mode - No automatic loading
const noneData = await fetchData({ id: 'noneData1' }, {
loadingMode: 'none',
autoLoad: false
});
```
### Virtual Fields
```typescript
// Set virtual field
await data.set("virtualField", value, true);
// Virtual fields are not saved to database
expect(data.virtual.virtualField).toBeDefined();
expect(data.original.virtualField).toBeUndefined();
```
### Parent-Child Component Relationships
```typescript
// Create parent component
const parentComp = new DEComp<any>(new Tag({id:'parent'}));
await parentComp.update({
controls: [
{tag: {id:'child1'}, name:'Child 1'},
{tag: {id:'child2'}, name:'Child 2'}
]
});
// Child components are automatically registered and inherit parent properties
const child1 = getComponent({id:'child1'});
expect(child1).toBeDefined();
```
## Performance Optimization
- Supports efficient handling of large datasets
- Supports data cache management
- Supports batch component registration and state updates
- Supports asynchronous loading and lazy initialization
## Important Notes
1. Data Object State Management
- Modified data enters dirty state
- Data updates to original state after submission
- Virtual fields are not saved to database
2. Component Lifecycle
- Mounting event triggered on component registration
- StateChanging event triggered on state changes
- WillUnmount event triggered on component unload
3. Data Loading Modes
- localDB: Suitable for local data storage
- custom: Suitable for custom data loading logic
- none: Suitable for manual data loading control
## Best Practices
1. Component Registration
- Use meaningful component IDs
- Properly utilize parent-child relationships
- Pay attention to component lifecycle management
2. Data Management
- Choose appropriate loading modes
- Properly use virtual fields
- Pay attention to data state management
3. Event Handling
- Properly use event pre-processing and post-processing
- Consider performance impact of event handling
- Avoid circular dependencies in event handling
---
# DEHub (中文)
DEHub 是一个基于 JavaScript 的客户端消息驱动库,通过消息订阅的方式统一处理客户端的事件与数据。它允许页面中的所有组件和业务流程以订阅的方式处理业务逻辑,并能够通过上下文访问所有已注册组件。
## 主要特性
- 组件注册与管理
- 支持组件的批量注册
- 支持组件的父子关系
- 支持组件的异步加载
- 支持组件的状态管理和更新
- 支持组件的生命周期事件
- 数据管理
- 支持多种数据加载模式(localDB, custom, none)
- 支持数据单例维护
- 支持虚拟字段(virtual fields)
- 支持数据重置和清理
- 支持数据缓存管理
- 支持大量数据的高性能处理
- 事件系统
- 支持事件订阅和处理
- 支持事件预处理和后处理
- 支持事件上下文访问
## 快速开始
### 组件注册
```typescript
// 创建并注册一个基础组件
const tag = new Tag({ id: 'cmp1' });
const comp1 = new DEComp<any>(tag);
await regComponent(comp1);
// 等待组件就绪
await comp1.waitReady();
// 更新组件状态
await comp1.update({ a: 1, b: 'abc' });
```
### 组件状态管理
```typescript
// 监听组件状态变更
when({
id: 'cmp1',
event: EventNames.StateChanging,
stage: EventStage.PostOperation
}, (context: EventContext) => {
const comp = context.sender as DEComp;
// 处理状态变更
});
// 更新组件状态
await comp1.update({ a: 2 });
```
### 数据管理
```typescript
// 创建数据标签
const IdTag = (entity: string, id: string): Tag => {
return new Tag({ entity, id });
};
// 获取数据对象
const user1Tag = IdTag('user.demo@org0', 'user1');
const user1Data = await fetchData(user1Tag, {
loadingMode: 'custom',
default: { name: 'Default' }
});
// 等待数据加载完成
await user1Data.until(ObjectStatus.Ready);
// 修改数据
await user1Data.set("name", "John");
await user1Data.set("age", 25);
// 提交数据
await user1Data.submit();
```
### 数据加载模式
```typescript
// LocalDB 模式 - 从本地数据库加载
const localData = await fetchData({ id: 'localData1' }, {
loadingMode: 'localDB',
default: { a: 1 }
});
// Custom 模式 - 自定义加载逻辑
const customData = await fetchData({ id: 'customData1' }, {
loadingMode: 'custom'
});
// None 模式 - 不自动加载
const noneData = await fetchData({ id: 'noneData1' }, {
loadingMode: 'none',
autoLoad: false
});
```
### 虚拟字段
```typescript
// 设置虚拟字段
await data.set("virtualField", value, true);
// 虚拟字段不会被保存到数据库
expect(data.virtual.virtualField).toBeDefined();
expect(data.original.virtualField).toBeUndefined();
```
### 组件父子关系
```typescript
// 创建父组件
const parentComp = new DEComp<any>(new Tag({id:'parent'}));
await parentComp.update({
controls: [
{tag: {id:'child1'}, name:'Child 1'},
{tag: {id:'child2'}, name:'Child 2'}
]
});
// 子组件会自动注册并继承父组件的属性
const child1 = getComponent({id:'child1'});
expect(child1).toBeDefined();
```
## 性能优化
- 支持大量数据对象的高效处理
- 支持数据缓存管理
- 支持组件的批量注册和状态更新
- 支持异步加载和延迟初始化
## 注意事项
1. 数据对象的状态管理
- 修改数据会进入 dirty 状态
- 提交后数据会更新到 original 状态
- 虚拟字段不会被保存到数据库
2. 组件生命周期
- 组件注册时会触发 Mounting 事件
- 状态变更时会触发 StateChanging 事件
- 组件卸载时会触发 WillUnmount 事件
3. 数据加载模式
- localDB: 适合本地数据存储
- custom: 适合自定义数据加载逻辑
- none: 适合手动控制数据加载
## 最佳实践
1. 组件注册
- 使用有意义的组件 ID
- 合理使用组件的父子关系
- 注意组件的生命周期管理
2. 数据管理
- 选择合适的加载模式
- 合理使用虚拟字段
- 注意数据状态的管理
3. 事件处理
- 合理使用事件预处理和后处理
- 注意事件处理的性能影响
- 避免事件处理的循环依赖