# 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. 事件处理
   - 合理使用事件预处理和后处理
   - 注意事件处理的性能影响
   - 避免事件处理的循环依赖
