UNPKG

dehub

Version:
354 lines (273 loc) 8.96 kB
# 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. 事件处理 - 合理使用事件预处理和后处理 - 注意事件处理的性能影响 - 避免事件处理的循环依赖