Hooks

2 阅读22分钟

项目所有 Hook 完整梳理(无限下钻)

本文档采用无限下钻的方式,详细梳理项目中所有 Hook 的原理、用法和底层机制。

目录


一、DataStorage 相关 Hooks(核心数据层)

1. useDataStorageObject - 获取单个对象

位置: packages/shared-library/src/hooks/UseDataStorageObject.ts

功能: 从 DataStorage 中获取单个对象,并在对象变化时自动更新组件

原理下钻:

useDataStorageObject(storage, id)
  ↓
1. 初始化阶段:
   - 从 storage.getObjectByID(id) 获取对象
   - 使用 useState 保存对象引用
   
2. 事件监听阶段:
   - storage.on("OBJECT_ADDED", updateObject)
   - storage.on("OBJECT_REMOVED", updateObject)  
   - storage.on("OBJECT_UPDATED", updateObject)
   
3. DataStorageWithFallback 支持:
   - 如果 storage 是 DataStorageWithFallback
   - 同时监听 fallbackStorage 的所有事件
   
4. 同步更新机制:
   - 使用 useMemo 确保在 id 变化时立即获取最新对象
   - finalObject = useMemo(() => storage?.getObjectByID(id), [id, currentObject])
   
5. 清理阶段:
   - 组件卸载时取消所有事件监听

核心机制详解:

  1. 事件驱动更新:

    // DataStorage 内部
    storage.putObject(newObject)
      → emit("OBJECT_ADDED", newObject)
      → Hook 的 onObjectsChanged 回调被触发
      → setCurrentObject(newObject)
      → React 组件重渲染
    
  2. 双重更新机制:

    • useState: 用于触发重渲染
    • useMemo: 用于在 id 变化时立即同步(不等待事件)
  3. Fallback Storage 支持:

    • DataStorageWithFallback 是包装器,内部有主 storage 和 fallback storage
    • Hook 需要同时监听两者,确保数据一致性

使用示例:

const [user] = useDataStorageObject(usersStorage, userId);

// user 会在以下情况自动更新:
// 1. storage.putObject(newUser) - 添加新用户
// 2. storage.removeObject(user) - 删除用户
// 3. user.setAttribute("name", "New Name") - 更新用户属性

性能考虑:

  • 只监听单个对象,性能开销小
  • 使用 useMemo 避免不必要的计算

2. useDataStorageObjects - 获取所有对象

位置: packages/shared-library/src/hooks/UseDataStorageObjects.ts

功能: 从 DataStorage 中获取所有对象列表,并在任何对象变化时自动更新

原理下钻:

useDataStorageObjects(storage, destroyStorageOnUnmount)
  ↓
1. 初始化阶段:
   - objects = storage.getAllObjects()
   - initialVersion.current = storage.getVersionNumber()
   - lastDataStorage.current = storage
   
2. 版本号检查机制:
   - 如果 storage.getVersionNumber() !== initialVersion.current
   - 或者 storage 引用变化
   - 立即更新 objects(不等待事件)
   
3. 微防抖优化:
   - 使用 useMicroDebounceHandler 包装更新函数
   - 避免在同一事件循环中多次 setState
   - 例如:添加 100 个对象 → 只更新一次
   
4. 事件监听:
   - storage.on("OBJECT_ADDED", onObjectsChanged)
   - storage.on("OBJECT_REMOVED", onObjectsChanged)
   - storage.on("OBJECT_UPDATED", onObjectsChanged)
   
5. 清理阶段:
   - 取消事件监听
   - 如果 destroyStorageOnUnmount === true,调用 storage.destroy()

核心机制详解:

  1. 版本号机制:

    // DataStorage 内部
    class DataStorage {
      private versionNumber = 0;
      
      putObject(obj) {
        this.versionNumber++; // 每次变化都递增
        this.emit("OBJECT_ADDED", obj);
      }
    }
    
    • 版本号用于检测 storage 是否在组件外部被更新
    • 如果版本号变化,说明数据已变化,需要立即同步
  2. 微防抖机制:

    // 批量操作场景
    for (let i = 0; i < 100; i++) {
      storage.putObject(newObject); // 触发 100 次 OBJECT_ADDED
    }
    // 使用微防抖后,onObjectsChanged 只执行一次
    
  3. 为什么需要版本号检查:

    • 如果 storage 在组件外部被更新(如另一个组件)
    • 事件可能已经触发,但当前组件还未订阅
    • 版本号检查确保不会丢失更新

使用示例:

const [users] = useDataStorageObjects(usersStorage);

// users 数组会在以下情况自动更新:
// 1. 任何用户被添加/删除/更新
// 2. storage 被外部组件修改

性能考虑:

  • 监听所有对象,性能开销较大
  • 使用微防抖减少更新频率
  • 适合列表渲染场景

3. useDataStorageLoadingState - Storage 加载状态

位置: packages/shared-library/src/hooks/UseDataStorageLoadingState.ts

功能: 跟踪 DataStorage 的整体加载状态

原理下钻:

useDataStorageLoadingState(storage)
  ↓
1. 获取 loadingObject:
   - loadingObject = storage.getLoadingObject()
   - loadingObject 是 ObjectWithEvents<{ isLoading: boolean }>
   
2. 初始化:
   - isLoading = loadingObject.getAttribute("isLoading")
   
3. 监听事件:
   - loadingObject.onAttributeChanged("isLoading", callback)
   
4. 返回:
   - [isLoading, setIsLoading]
   - setIsLoading → storage.setIsLoading(isLoading)

底层机制:

  • DataStorage 内部维护 loadingObject
  • setIsLoading(true)loadingObject.setAttribute("isLoading", true) → 触发事件
  • Hook 监听事件 → 更新 React state

使用示例:

const [isLoading, setIsLoading] = useDataStorageLoadingState(usersStorage);

// 开始加载
setIsLoading(true);
await fetchUsers();
setIsLoading(false);

4. useDataStorageObjectsWithIds - 按 ID 列表获取对象

位置: packages/shared-library/src/hooks/UseDataStorageObjectsWithIds.ts

功能: 根据 ID 列表获取多个对象

原理: 遍历 ID 列表,使用 storage.getObjectByID(id) 获取每个对象


5. useDataStorageViewObjects - 获取视图对象

位置: packages/shared-library/src/hooks/UseDataStorageViewObjects.ts

功能: 获取 DataStorage 的视图对象(经过过滤/排序后的对象)


6. useDataStorageVersion - 获取 Storage 版本号

位置: packages/shared-library/src/hooks/UseDataStorageVersion.ts

功能: 跟踪 DataStorage 的版本号变化

原理: 监听 storage.getVersionNumber() 的变化


二、ObjectWithEvents 相关 Hooks(状态对象层)

7. useObjectAttribute - 单个属性

位置: packages/shared-library/src/hooks/UseObjectAttribute.ts

功能: 从 ObjectWithEvents 中获取单个属性,并在属性变化时自动更新

原理下钻:

useObjectAttribute(object, attributeName)
  ↓
1. 初始化:
   - attribute = object.getAttribute(attributeName)
   
2. 监听事件:
   - object.onAttributeChanged(attributeName, callback)
   
3. 同步检查(防止事件丢失):
   - 如果 attribute !== object.getAttribute(attributeName)
   - 立即同步(在 useEffect 中)
   
4. 返回:
   - [attribute, setAttributeHandler]
   - setAttributeHandler → object.setAttribute(attributeName, value)

底层机制详解:

  1. ObjectWithEvents 内部结构:

    class ObjectWithEvents<Attributes> {
      protected attributesChangedEvents: EventEmitter<EventsMap<Attributes>>;
      
      setAttribute(name, value) {
        this.attributes[name] = value;
        this.attributesChangedEvents.emit(name, value); // 触发事件
      }
      
      onAttributeChanged(name, callback) {
        this.attributesChangedEvents.on(name, callback);
      }
    }
    
  2. 为什么需要同步检查:

    • 如果 object 在组件外部被更新
    • 事件可能已经触发,但组件还未订阅
    • 同步检查确保不会丢失最新值

使用示例:

const [count, setCount] = useObjectAttribute(counterObject, "count");

// count 会在以下情况自动更新:
// 1. counterObject.setAttribute("count", 10)
// 2. counterObject.setAttributes({ count: 10 })

8. useObjectAttributes - 所有属性

位置: packages/shared-library/src/hooks/UseObjectAttributes.ts

功能: 从 ObjectWithEvents 中获取所有属性

原理下钻:

useObjectAttributes(object)
  ↓
1. 初始化:
   - objectAttributes = object.getAttributes()
   - 返回所有属性的对象:{ attr1: value1, attr2: value2, ... }
   
2. 监听事件:
   - object.onObjectChanged(callback)
   - 注意:监听的是 OBJECT_CHANGED 事件,不是单个属性
   
3. 返回:
   - [objectAttributes, setAttributesHandler]
   - setAttributesHandler → object.setAttributes(newAttributes)

与 useObjectAttribute 的区别:

特性useObjectAttributeuseObjectAttributes
监听事件onAttributeChanged(attrName)onObjectChanged()
触发时机setAttribute(name, value)setAttributes({...})
返回类型单个属性值所有属性的对象
使用场景只需要单个属性需要多个属性

使用示例:

const [attributes, setAttributes] = useObjectAttributes(userObject);

// attributes = { name: "John", age: 30, email: "john@example.com" }
// 更新多个属性
setAttributes({ name: "Jane", age: 31 });

三、Model Loading 相关 Hooks(加载状态层)

9. useModelLoadingIdState - 按 ID 的加载状态

位置: packages/shared-library/src/hooks/UseModelLoadingIdState.ts

功能: 跟踪 Model 中特定 ID 的加载状态(细粒度)

原理下钻:

useModelLoadingIdState(model, id)
  ↓
1. 获取 loadingObject:
   - loadingObject = model.getLoadingObject()
   - loadingObject 是 ObjectWithEvents<{ isLoading: boolean; [key: string]: boolean }>
   
2. 初始化:
   - isLoading = model.isLoadingObjectId(id)
   - 内部:loadingObject.getAttribute(`id:${id}`)
   
3. ID 变化处理:
   - useEffect 监听 id 变化
   - 立即更新状态:setIsLoading(model.isLoadingObjectId(id))
   
4. 监听事件:
   - loadingObject.onAttributeChanged(`id:${id}`, callback)
   - 注意:事件名称是 `id:${id}`,不是 `isLoading`
   
5. 返回:
   - [isLoading, setLoadingHandlerState]
   - setLoadingHandlerState → model.setLoadingObjectId(id, isLoading)

底层机制详解:

  1. AbstractDataModel 的 loadingObject:

    class AbstractDataModel {
      protected loadingObject: ObjectWithEvents<{
        isLoading: boolean;
        [key: string]: boolean; // 支持动态属性:id:endpoint1, id:endpoint2
      }>;
      
      setLoadingObjectId(id: string, isLoading: boolean) {
        this.loadingObject.setAttribute(`id:${id}`, isLoading);
      }
      
      isLoadingObjectId(id: string) {
        return this.loadingObject.getAttribute(`id:${id}`) || false;
      }
    }
    
  2. 为什么使用 id:${id} 作为属性名:

    • 支持同时跟踪多个 ID 的加载状态
    • id:endpoint1 = true, id:endpoint2 = false
    • 每个 ID 独立跟踪,互不影响
  3. ID 变化处理的重要性:

    • 如果 id 从 "endpoint1" 变为 "endpoint2"
    • 需要立即取消对 id:endpoint1 的监听
    • 开始监听 id:endpoint2

使用示例:

const [isLoading] = useModelLoadingIdState(workloadDataModel, endpointId);

// 在 Fetcher 中
workloadDataModel.setLoadingObjectId(endpointId, true);
await fetchEndpointData(endpointId);
workloadDataModel.setLoadingObjectId(endpointId, false);

使用场景:

  • 侧边栏打开某个 endpoint 详情
  • 只显示该 endpoint 的 loading,不影响其他组件

10. useModelOrStorageLoadingState - 整体加载状态

位置: packages/shared-library/src/hooks/UseModelOrStorageLoadingState.ts

功能: 跟踪 Model 或 Storage 的整体加载状态(粗粒度)

原理下钻:

useModelOrStorageLoadingState(modelOrStorage)
  ↓
1. 获取 loadingObject:
   - loadingObject = modelOrStorage.getLoadingObject()
   
2. 初始化:
   - isLoading = loadingObject.getAttribute("isLoading")
   
3. 监听事件:
   - loadingObject.onAttributeChanged("isLoading", callback)
   
4. 返回:
   - [isLoading, setLoadingHandlerState]
   - setLoadingHandlerState → modelOrStorage.setIsLoading(isLoading)

与 useModelLoadingIdState 的区别:

特性useModelLoadingIdStateuseModelOrStorageLoadingState
粒度细粒度(按 ID)粗粒度(整体)
属性名id:${id}isLoading
使用场景特定资源的加载整个 Model/Storage 的加载
影响范围只影响特定 ID影响所有使用该 Model 的组件

使用示例:

const [isLoading, setIsLoading] = useModelOrStorageLoadingState(workloadDataModel);

// 开始加载整个 Model
setIsLoading(true);
await loadAllWorkloadData();
setIsLoading(false);

11. useLoader - 全局 Loader 状态

位置: packages/console/src/hooks/UseLoader.ts

功能: 跟踪全局预定义的 Loader 状态(页面/功能级别)

原理下钻:

useLoader(loaderName)
  ↓
1. 获取 loaderObject:
   - appController = useContext(AppControllerContext)
   - loaderObject = appController.loaderStatesManager.getLoaderObject()
   
2. 初始化:
   - isLoading = loaderObject.getAttribute(loaderName)
   
3. 监听事件:
   - loaderObject.onAttributeChanged(loaderName, callback)
   
4. 返回:
   - [isLoading, setLoadingState]
   - setLoadingState → loaderObject.setAttribute(loaderName, isLoading)

底层机制详解:

  1. LoaderStatesManager:

    class LoaderStatesManager {
      private loaderStates: ObjectWithEvents<LoadersType>;
      
      constructor() {
        this.loaderStates = new ObjectWithEvents({
          WORKLOAD_MAP_LOADER: true,
          THREATS_DETECTIONS_LOADER: true,
          // ... 预定义的所有 loader
        });
      }
      
      setLoaderState(loaderName: LoaderNames, state: boolean) {
        this.loaderStates.setAttribute(loaderName, state);
      }
    }
    
  2. 预定义的 Loader 名称:

    export enum LoaderNames {
      WORKLOAD_MAP_LOADER = "WORKLOAD_MAP_LOADER",
      THREATS_DETECTIONS_LOADER = "THREATS_DETECTIONS_LOADER",
      // ... 30+ 个预定义的 loader
    }
    
  3. 全局单例:

    • LoaderStatesManagerAppController 中创建
    • 所有组件共享同一个实例
    • 适合页面级别的 loading 状态

使用示例:

const [isPageLoading] = useLoader(LOADERS.WORKLOAD_MAP_LOADER);

// 在 Controller 中
loaderStatesManager.setLoaderState(LOADERS.WORKLOAD_MAP_LOADER, true);
await loadInitialPageData();
loaderStatesManager.setLoaderState(LOADERS.WORKLOAD_MAP_LOADER, false);

使用场景:

  • 页面初始加载
  • 整个表格刷新
  • 全局功能级别的 loading

12. useLoaders - 多个 Loader 状态

位置: packages/console/src/hooks/UseLoaders.ts

功能: 同时跟踪多个 Loader 状态

原理: 对每个 loaderName 调用 useLoader,返回合并后的状态


四、Filter 相关 Hooks(过滤层)

13. useFilters - 过滤器状态

位置: packages/shared-library/src/hooks/UseFilters.ts

功能: 管理 DataStorageWithFilters 的过滤器状态

原理下钻:

useFilters(storageOrDataModel)
  ↓
1. 初始化:
   - selectedFilters = storageOrDataModel.getFilters()
   
2. 监听事件:
   - storageOrDataModel.on("FILTERS_CHANGED", onFiltersChanged)
   
3. 深度比较:
   - 使用 deepCompare 避免不必要的更新
   - 如果 filters 引用变化但内容相同,不更新
   
4. 双向绑定:
   - setFilters → storageOrDataModel.setFilters(newFilters)
   - 如果 storageOrDataModel 有 "on" 方法(支持事件):
     - 通过事件自动更新(不需要手动 setState)
   - 否则:
     - 手动 setState
   
5. 返回:
   - [selectedFilters, setFiltersCallback]

底层机制详解:

  1. DataStorageWithFilters:

    class DataStorageWithFilters extends DataStorage {
      setFilters(filters: FilterOption[]) {
        this.filters = filters;
        this.applyFilters(); // 应用过滤
        this.emit("FILTERS_CHANGED", filters); // 触发事件
      }
    }
    
  2. 深度比较的重要性:

    • 如果 filters 数组引用变化但内容相同
    • 不应该触发更新(避免无限循环)
  3. 事件驱动的双向绑定:

    • 组件调用 setFilters → 更新 storage
    • Storage 触发 FILTERS_CHANGED 事件 → 更新组件 state
    • 形成闭环,确保数据一致性

使用示例:

const [filters, setFilters] = useFilters(filterableStorage);

// 更新过滤器
setFilters([
  {
    filterType: "STATUS",
    filterOptions: new Set(["active"]),
    method: FILTER_METHOD.INCLUDE
  }
]);

// filters 会在 storage.setFilters() 时自动更新

五、Router 相关 Hooks(路由层)

14. useRouterAttribute - 路由属性绑定

位置: packages/console/src/hooks/UseRouterAttribute.ts

功能: 将 React 组件状态与 Router 属性双向绑定

原理下钻:

useRouterAttribute(router, attributeName)
  ↓
1. 获取当前值:
   - value = router.getAttribute(attributeName)
   
2. 注册层参数:
   - routeLayer = useLayerPath()
   - router.registerLayerParam(routeLayer, attributeName, value)
   - 用于多层级路由管理
   
3. 监听事件:
   - router.events.on(`changed:${attributeName}`, onAttributeChanged)
   
4. 更新路由:
   - setRouterAttribute → router.pushAttributes({ [attributeName]: newValue })
   - pushAttributes 会更新 URL,并触发 changed 事件
   
5. 清理:
   - router.unregisterLayerParam(routeLayer, attributeName)

底层机制详解:

  1. Router 内部结构:

    class Router {
      private attributes: RouterAttributes;
      public events: EventEmitter;
      
      getAttribute(name) {
        return this.attributes[name];
      }
      
      pushAttributes(newAttributes, replace = false) {
        // 更新内部 attributes
        this.attributes = { ...this.attributes, ...newAttributes };
        // 更新 URL
        this.updateURL();
        // 触发事件
        Object.keys(newAttributes).forEach(key => {
          this.events.emit(`changed:${key}`, newAttributes[key]);
        });
      }
    }
    
  2. 多层级路由管理:

    • routeLayer 用于区分不同层级的路由(如 SidePane 1, SidePane 2)
    • registerLayerParam 注册当前层级的参数
    • 确保不同层级的参数不会冲突
  3. 双向绑定流程:

    组件调用 setRouterAttribute("tab1")
      → router.pushAttributes({ mainPageTab: "tab1" })
      → 更新 URL: /inventory?mainPageTab=tab1
      → 触发 changed:mainPageTab 事件
      → Hook 的 onAttributeChanged 回调
      → 更新组件 state
    

使用示例:

const [selectedTab, setSelectedTab] = useRouterAttribute(router, "mainPageTab");

// 更新 tab
setSelectedTab("workloads");

// selectedTab 会在以下情况自动更新:
// 1. URL 变化:/inventory?mainPageTab=accounts
// 2. 其他组件调用 setSelectedTab

六、Model 管理相关 Hooks(模型层)

15. useModel - 获取/创建 Model

位置: packages/console/src/hooks/UseModel.ts

功能: 从 PanesModels 注册表中获取或创建 Model,支持引用计数和生命周期管理

原理下钻:

useModel(modelType, itemId, modelConstructor)
  ↓
1. 获取 PanesModels:
   - panesModels = appController.appDataModel.panesModels
   - PanesModels 是 Model 的注册表
   
2. 检查现有 Model:
   - existingModel = panesModels.getModel(modelType, itemId)
   
3. 创建新 Model(如果需要):
   - 如果 !existingModel && modelConstructor
   - newModel = modelConstructor()
   - panesModels.addModel(modelType, itemId, newModel)
   - isCreatedModel = true
   
4. 引用计数管理:
   - panesModels.addReferenceCount(modelType, itemId)
   - 组件卸载时:panesModels.removeReferenceCount(modelType, itemId)
   - 当引用计数为 0 时,Model 可以被清理
   
5. 监听 Model 变化:
   - panesModels.on("MODEL_ADDED", onModelAdded)
   - panesModels.on("MODEL_REMOVED", onModelRemoved)
   
6. 加载状态:
   - [isLoading, setIsLoading] = useModelOrStorageLoadingState(model)
   
7. 返回:
   - [model, isCreatedModel, isLoading, setIsLoading]

底层机制详解:

  1. PanesModels 注册表:

    class PanesModels {
      private models: Map<ModelType, Map<string, Model>>;
      private referenceCounts: Map<string, number>;
      
      getModel(type: ModelType, itemId: string) {
        return this.models.get(type)?.get(itemId);
      }
      
      addModel(type: ModelType, itemId: string, model: Model) {
        if (!this.models.has(type)) {
          this.models.set(type, new Map());
        }
        this.models.get(type)!.set(itemId, model);
        this.emit("MODEL_ADDED", { type, itemId });
      }
      
      addReferenceCount(type: ModelType, itemId: string) {
        const key = `${type}:${itemId}`;
        const count = this.referenceCounts.get(key) || 0;
        this.referenceCounts.set(key, count + 1);
      }
      
      removeReferenceCount(type: ModelType, itemId: string) {
        const key = `${type}:${itemId}`;
        const count = this.referenceCounts.get(key) || 1;
        if (count === 1) {
          // 引用计数为 0,可以清理 Model
          this.removeModel(type, itemId);
        } else {
          this.referenceCounts.set(key, count - 1);
        }
      }
    }
    
  2. 引用计数的作用:

    • 多个组件可以共享同一个 Model
    • 例如:SidePane 和 FloatingPane 使用同一个 DetectionSidePaneModel
    • 只有当所有组件都卸载时,Model 才被清理
  3. Model 生命周期:

    组件 A 调用 useModel → 创建 Model → 引用计数 = 1
    组件 B 调用 useModel(相同 type + itemId)→ 复用 Model → 引用计数 = 2
    组件 A 卸载 → 引用计数 = 1
    组件 B 卸载 → 引用计数 = 0 → 清理 Model
    

使用示例:

const [detectionModel, isCreated, isLoading, setIsLoading] = useModel(
  "DetectionSidePaneModel",
  sidePaneItemId,
  () => new DetectionSidePaneModel(sharedModel)
);

// isCreated 可以用于判断是否需要加载数据
if (isCreated) {
  setIsLoading(true);
  await loadDetectionData(detectionModel);
  setIsLoading(false);
}

16. useSidePaneModel - SidePane Model

位置: packages/console/src/hooks/UseSidePaneModel.ts

功能: 获取 SidePane 对应的 Model,支持 SidePane 和 FloatingPane 共享

原理下钻:

useSidePaneModel(modelType, modelConstructor, isPreviousSidePanel)
  ↓
1. 获取 SidePane 信息:
   - sidePaneType = useSidePaneType(isPreviousSidePanel)
   - sidePaneItemId = useSidePaneItemId(isPreviousSidePanel)
   
2. 构建 itemId:
   - itemId = sidePaneType + ":" + sidePaneItemId
   - 例如:"CloudAccountSidePane:account-123"
   
3. 调用 useModel:
   - useModel(modelType, itemId, modelConstructor)

设计目的:

  1. SidePane 和 FloatingPane 共享 Model:

    • FloatingPane 2 使用 SidePane 2 的 Model
    • 通过 sidePaneType + ":" + sidePaneItemId 确保匹配
  2. 多 SidePane 支持:

    • 系统支持 3 个 SidePane(1, 2, 3)
    • 每个 SidePane 有独立的 Model

使用示例:

// 在 SidePane 中
const [detectionModel] = useSidePaneModel(
  "DetectionSidePaneModel",
  () => new DetectionSidePaneModel(sharedModel)
);

// 在对应的 FloatingPane 中
const [detectionModel] = useSidePaneModel("DetectionSidePaneModel");
// 会自动获取同一个 Model

七、AsyncStorage 相关 Hooks(异步数据层)

17. useAsyncStorageObject - 异步获取对象

位置: packages/shared-library/src/hooks/UseAsyncStorageObject.ts

功能: 从 AsyncStorage 中异步获取对象,支持懒加载和错误处理

原理下钻:

useAsyncStorageObject(asyncStorage, id)
  ↓
1. 初始化状态:
   - object = asyncStorage.getObjectByID(id) || null
   - isLoadingObject = !Boolean(object)
   - error = asyncStorage.getObjectErrorById(id)
   
2. ID 变化处理:
   - 如果 object 存在且 object.getId() === id
     → 直接返回(对象已存在)
   - 否则:
     → 检查 asyncStorage.getObjectByID(id)
     → 如果存在 → 更新 object
     → 如果不存在 → 调用 asyncStorage.getAsyncObjectById(id, callback)
   
3. 异步回调处理:
   - onObjReceived(obj, error)
     → setObject(obj)
     → setIsLoadingObject(false)
     → setError(error)
   
4. 清理:
   - asyncStorage.cancelGetObjectById(id, callback)

底层机制详解:

  1. AsyncStorage:

    class AsyncStorage<T extends StorageObject> {
      private objects: Map<string, T>;
      private loadingPromises: Map<string, Promise<T | null>>;
      private errors: Map<string, any>;
      
      getObjectByID(id: string) {
        return this.objects.get(id);
      }
      
      getAsyncObjectById(id: string, callback: (obj: T | null, error: any) => void) {
        // 如果正在加载,复用 Promise
        if (this.loadingPromises.has(id)) {
          this.loadingPromises.get(id)!.then(callback);
          return;
        }
        
        // 创建新的加载 Promise
        const promise = this.fetchObjectFromServer(id)
          .then(obj => {
            this.objects.set(id, obj);
            callback(obj, null);
            return obj;
          })
          .catch(error => {
            this.errors.set(id, error);
            callback(null, error);
            throw error;
          })
          .finally(() => {
            this.loadingPromises.delete(id);
          });
        
        this.loadingPromises.set(id, promise);
      }
      
      cancelGetObjectById(id: string, callback: Function) {
        // 取消回调(实际实现可能更复杂)
      }
    }
    
  2. 懒加载机制:

    • 只有当对象不存在时,才触发 API 请求
    • 如果对象已存在,直接返回(不发起请求)
  3. 错误处理:

    • 支持存储和显示错误信息
    • getObjectErrorById(id) 获取特定对象的错误

使用示例:

const [flowThroughput, isLoading, error] = useAsyncStorageObject(
  flowThroughputAsyncStorage,
  flowId
);

// 如果 flowThroughput 不存在,会自动触发 API 请求
// isLoading 会在请求过程中为 true
// error 会在请求失败时包含错误信息

18. useAsyncStorageSource - 异步 Storage 源

位置: packages/shared-library/src/hooks/UseAsyncStorageSource.ts

功能: 获取 AsyncStorage 的数据源信息


八、性能优化相关 Hooks

19. useDebounce - 防抖

位置: packages/shared-library/src/hooks/UseDebounce.ts

功能: 防抖函数,延迟执行直到停止调用一段时间

原理下钻:

useDebounce(func, delay, dependencies)
  ↓
1. 使用 useCallback 包装 func:
   - callback = useCallback(func, dependencies)
   
2. 使用 useRef 保存最新回调:
   - callbackRef.current = callback
   - 确保使用最新版本的函数
   
3. 返回防抖函数:
   - 每次调用 → clearTimeout(previous)
   - setTimeout(() => callbackRef.current(...args), delay)
   
4. 清理:
   - useEffect 返回清理函数 → clearTimeout

使用示例:

const debouncedSearch = useDebounce((query: string) => {
  searchAPI(query);
}, 500, []);

// 用户输入时
debouncedSearch("a"); // 取消,不执行
debouncedSearch("ab"); // 取消,不执行
debouncedSearch("abc"); // 500ms 后执行 searchAPI("abc")

20. useMicroDebounceHandler - 微防抖

位置: packages/shared-library/src/hooks/UseMicroDebounceHandler.ts

功能: 微防抖,延迟到当前事件循环结束

原理下钻:

useMicroDebounceHandler(callbackFn, dependencies)
  ↓
1. 使用 useCallback 包装 callbackFn
2. 使用 useRef 保存 latestFn
3. 使用 inProgressRef 防止重复调用
4. 返回防抖函数:
   - 如果 inProgressRef.current === true → 直接返回
   - 否则:
     - inProgressRef.current = true
     - Promise.resolve().then(() => {
         inProgressRef.current = false
         if (mounted.current) latestFn.current()
       })
5. 清理:
   - mounted.current = false

与 useDebounce 的区别:

特性useDebounceuseMicroDebounceHandler
延迟方式setTimeoutPromise.resolve()
延迟时间固定(如 500ms)当前事件循环结束(几乎立即)
使用场景用户输入防抖批量操作优化

使用场景:

// 批量添加对象
const onObjectsChanged = useMicroDebounceHandler(() => {
  setObjects(storage.getAllObjects());
}, [storage]);

// 添加 100 个对象
for (let i = 0; i < 100; i++) {
  storage.putObject(newObject); // 触发 100 次事件
}
// onObjectsChanged 只执行一次(在当前事件循环结束后)

九、Utility Hooks

21. useToggle - 切换状态

位置: packages/shared-library/src/hooks/UseToggle.ts

功能: 简单的 boolean 状态切换

返回: [isEnabled, toggleIsEnabled, { setIsEnabled, markAsEnabled, markAsDisabled }]


22. useControllableState - 可控/不可控状态

位置: packages/shared-library/src/hooks/UseControllableState.ts

功能: 支持受控和不受控两种模式的组件状态

原理: 根据 controlledValue 是否存在判断模式


23. useTheme - 主题

位置: packages/shared-library/src/hooks/useTheme.ts

功能: 从 ThemeContext 获取主题信息


24. useLocalStorage - 本地存储

位置: packages/shared-library/src/hooks/UseLocalStorage.ts

功能: 将状态同步到 localStorage


25. useOnClickOutside - 点击外部

位置: packages/shared-library/src/hooks/UseOnClickOutside.ts

功能: 检测点击是否在元素外部


26. useElementSize - 元素尺寸

位置: packages/shared-library/src/hooks/UseElementSize.ts

功能: 跟踪 DOM 元素的尺寸变化


27. useMediaQuery - 媒体查询

位置: packages/shared-library/src/hooks/UseMediaQuery.tsx

功能: 响应式设计,检测媒体查询匹配


十、Console 特定 Hooks

28. usePaneResource - Pane 资源

位置: packages/console/src/hooks/UsePaneResource.ts

功能: 从多个数据源获取 SidePane/FloatingPane 的资源

原理下钻:

usePaneResource(resourceId, paneManager)
  ↓
1. 获取多个 Storage:
   - resourcesStorage(主资源 Storage)
   - imageResourcesStorage(镜像相关资源)
   - packageResourcesStorage(包相关资源)
   - workloadEndpointsStorage(工作负载端点)
   - storyIssueSidePaneResourcesStorage(故事问题资源)
   
2. 使用 useDataStorageObject 从每个 Storage 获取对象:
   - _resourceObject = useDataStorageObject(resourcesStorage, resourceId)
   - imageResourceObject = useDataStorageObject(imageResourcesStorage, resourceId)
   - ...
   
3. 合并结果:
   - resource = _resourceObject || imageResourceObject || packageResourceObject || ...
   - 按优先级返回第一个存在的对象
   
4. 合并加载状态:
   - isLoading = resourceStorageLoading || isLoadingImageModel || ...
   - 如果 resource 存在,isLoading = false

设计目的:

  • SidePane 可能从多个数据源获取资源
  • 需要按优先级合并显示
  • 需要合并所有数据源的加载状态

29. useCloudAccount - 云账户

位置: packages/console/src/hooks/useCloudAccount.ts

功能: 从 sharedModel 获取云账户信息


30. useCloudAccounts - 云账户列表

位置: packages/console/src/hooks/useCloudAccounts.ts

功能: 获取所有云账户


31. useRouterAttribute - 路由属性(已在第五部分说明)


32. useSelectedTab - 选中的 Tab

位置: packages/console/src/hooks/UseSelectedTab.ts

功能: 从 Router 获取当前选中的 Tab


33. useQueryFromUrl - URL 查询参数

位置: packages/console/src/hooks/UseQueryFromUrl.ts

功能: 从 URL 查询参数中获取值


34. useSavedQuery - 保存的查询

位置: packages/console/src/hooks/UseSavedQuery.ts

功能: 管理保存的查询条件


35. usePermission - 权限检查

位置: packages/console/src/hooks/UsePermission.ts

功能: 检查用户是否有特定权限(RBAC)


36. useIsUpwindUser - 是否是 Upwind 用户

位置: packages/console/src/hooks/UseIsUpwindUser.ts

功能: 检查当前用户是否是 Upwind 内部用户


37. useUserInfo - 用户信息

位置: packages/console/src/hooks/useUserInfo.ts

功能: 获取当前用户信息


38. useUserSelectedOrganization - 用户选择的组织

位置: packages/console/src/hooks/UseUserSelectedOrganization.ts

功能: 获取用户当前选择的组织


39. useSharedModel - 共享 Model

位置: packages/console/src/hooks/useSharedModel.ts

功能: 获取 AppDataModel 的 sharedModel


40. useConsoleRequestState - Console 请求状态

位置: packages/console/src/hooks/useConsoleRequestState.ts

功能: 跟踪 Console 特定请求的状态(支持 RBAC 错误处理)


41. useRbacDisableButton - RBAC 按钮禁用

位置: packages/console/src/hooks/useRbacPermission/useRbacDisableButton.tsx

功能: 根据 RBAC 权限禁用按钮,返回 tooltip 内容


42. useOpenSidePane - 打开 SidePane

位置: packages/console/src/hooks/useOpenSidePane.tsx

功能: 打开 SidePane 的便捷方法


43. useOpenFloatingPane - 打开 FloatingPane

位置: packages/console/src/hooks/useOpenFloatingPane.tsx

功能: 打开 FloatingPane 的便捷方法


44. useResourceOverviewTabs - 资源概览 Tabs

位置: packages/console/src/hooks/useResourceOverviewTabs.tsx

功能: 管理资源概览页面的 Tabs


45. useResourceOverviewTabsData - 资源概览 Tabs 数据

位置: packages/console/src/hooks/useResourceOverviewTabsData.tsx

功能: 获取资源概览 Tabs 的数据


46. useGraphAssetById - 通过 ID 获取 Graph Asset

位置: packages/console/src/hooks/UseGraphAssetById.ts

功能: 从 Graph Model 中获取 Asset


47. useGraphAssetHeaderDetails - Graph Asset 头部详情

位置: packages/console/src/hooks/UseGraphAssetHeaderDetails.tsx

功能: 获取 Graph Asset 的头部显示信息


48. useWorkloadDuration - 工作负载时长

位置: packages/console/src/hooks/UseWorkloadDuration.tsx

功能: 计算和格式化工作负载的时间范围


49. useMapSelection - Map 选择

位置: packages/console/src/hooks/UseMapSelection.ts

功能: 管理 Workload Map 的选择状态


50. useMapView - Map 视图

位置: packages/console/src/hooks/UseMapView.ts

功能: 管理 Workload Map 的视图状态


51. useMapReady - Map 就绪状态

位置: packages/console/src/hooks/UseMapReady.ts

功能: 检测 Workload Map 是否已就绪


52. useSelection - 选择状态

位置: packages/console/src/hooks/UseSelection.ts

功能: 管理通用选择状态


53. useSelectionSet - 选择集合

位置: packages/console/src/hooks/UseSelectionSet.ts

功能: 管理选择集合(多个选中项)


54. useTreeStorageObject - Tree Storage 对象

位置: packages/console/src/hooks/UseTreeStorageObject.ts

功能: 从 WorkloadTreeStorage 获取对象


55. usePaneResource - Pane 资源(已在前面说明)


56. useCustomConnectionDataModel - 自定义连接数据 Model

位置: packages/console/src/hooks/UseCustomConnectionDataModel.ts

功能: 为自定义时间范围创建独立的 WorkloadDataModel


57. useFlowsOfSelection - 选中项的 Flows

位置: packages/console/src/hooks/useFlowsOfSelection.ts

功能: 获取选中项相关的流量数据


58. useFlowsOfSelectedElement - 选中元素的 Flows

位置: packages/console/src/hooks/UseFlowsOfSelectedElement.ts

功能: 获取选中元素相关的流量数据


59. useEndpointsOfTreeStorage - Tree Storage 的 Endpoints

位置: packages/console/src/hooks/UseEndpointsOfTreeStorage.ts

功能: 从 WorkloadTreeStorage 获取所有 Endpoints


60. useParentTreeStorageOfEndpoint - Endpoint 的父 Tree Storage

位置: packages/console/src/hooks/UseParentTreeStorageOfEndpoint.ts

功能: 获取包含特定 Endpoint 的父 Tree Storage


61. useAggregatedEndpointFlows - 聚合 Endpoint Flows

位置: packages/console/src/hooks/UseAggregatedEndpointFlows.ts

功能: 获取聚合后的 Endpoint 流量数据


62. useConnectionTableRows - 连接表格行

位置: packages/console/src/hooks/UseConnectionTableRows.ts

功能: 生成连接表格的行数据


63. useAsyncFiltersTableRows - 异步过滤表格行

位置: packages/console/src/hooks/UseAsyncFiltersTableRows.ts

功能: 使用异步过滤器生成表格行数据


64. useCachedRows - 缓存行

位置: packages/console/src/hooks/UseCachedRows.ts

功能: 缓存表格行数据,避免重复计算


65. useTableRowDataWithFilterBar - 带过滤栏的表格行数据

位置: packages/console/src/hooks/UseTableRowDataWithFilterBar.ts

功能: 结合过滤栏生成表格行数据


66. useTableDataSource - 表格数据源

位置: packages/console/src/hooks/useTableDataSource.tsx

功能: 管理表格的数据源


67. useConfigurationsFindingFieldCount - 配置发现字段计数

位置: packages/console/src/hooks/UseConfigurationsFindingFieldCount.ts

功能: 计算配置发现的字段数量


68. useUpdateDetectionStatus - 更新检测状态

位置: packages/console/src/hooks/UseUpdateDetectionStatus.ts

功能: 更新检测(Detection)的状态


69. useUpdateDetectionStatusOptions - 更新检测状态选项

位置: packages/console/src/hooks/UseUpdateDetectionStatusOptions.tsx

功能: 获取可用的检测状态更新选项


70. useUpdateIssueStatusOptions - 更新问题状态选项

位置: packages/console/src/hooks/UseUpdateIssueStatusOptions.ts

功能: 获取可用的问题状态更新选项


71. useTestSamlConnection - 测试 SAML 连接

位置: packages/console/src/hooks/UseTestSamlConnection.ts

功能: 测试 SAML 连接配置


72. useUpwindIntegrationsConnection - Upwind 集成连接

位置: packages/console/src/hooks/UseUpwindIntegrationsConnection.ts

功能: 管理 Upwind 集成连接状态


73. useSharedTabsConnectionStatus - 共享 Tabs 连接状态

位置: packages/console/src/hooks/UseSharedTabsConnectionStatus.ts

功能: 管理共享 Tabs 的连接状态


74. useTabsWithFeatureFlags - 带功能标志的 Tabs

位置: packages/console/src/hooks/UseTabsWithFeatureFlags.tsx

功能: 根据功能标志过滤 Tabs


75. useTabActivator - Tab 激活器

位置: packages/console/src/hooks/UseTabActivator.ts

功能: 激活特定的 Tab


76. useSelectedTabWithIndex - 带索引的选中 Tab

位置: packages/console/src/hooks/UseSelectedTabWithIndex.ts

功能: 获取选中 Tab 及其索引


77. useResourceLastFetchTime - 资源最后获取时间

位置: packages/console/src/hooks/UseResourceLastFetchTime.tsx

功能: 跟踪资源数据的最后获取时间


78. useResourceOverviewDetails - 资源概览详情

位置: packages/console/src/hooks/UseResourceOverviewDetails.ts

功能: 获取资源概览的详细信息


79. useSidePaneFilters - SidePane 过滤器

位置: packages/console/src/hooks/UseSidePaneFilters.ts

功能: 管理 SidePane 的过滤器状态


80. useSidePaneStorage - SidePane Storage

位置: packages/console/src/hooks/UseSidePaneStorage.ts

功能: 获取 SidePane 对应的 Storage


81. useSidePaneAttributeName - SidePane 属性名

位置: packages/console/src/hooks/useSidePaneAttributeName.ts

功能: 获取 SidePane 的属性名


82. useSidePaneAccountsFilter - SidePane 账户过滤器

位置: packages/console/src/hooks/useSidePaneAccountsFilter.ts

功能: 管理 SidePane 的账户过滤器


83. useRelatedPaneAttributeNames - 相关 Pane 属性名

位置: packages/console/src/hooks/UseRelatedPaneAttributeNames.ts

功能: 获取相关 Pane 的属性名(如 sidePaneType, sidePaneItemId)


84. useEndpointIdByRefId - 通过 RefId 获取 EndpointId

位置: packages/console/src/hooks/UseEndpointIdByRefId.ts

功能: 通过 RefId 异步获取 EndpointId


85. useFetchRelatedGraphAssets - 获取相关 Graph Assets

位置: packages/console/src/hooks/useFetchRelatedGraphAssets.ts

功能: 获取与当前资源相关的 Graph Assets


86. useFetchRelatedScalingGroup - 获取相关扩展组

位置: packages/console/src/hooks/useFetchRelatedScalingGroup.ts

功能: 获取与当前资源相关的扩展组


87. useProcessWithActiveOverride - 带活动覆盖的进程

位置: packages/console/src/hooks/useProcessWithActiveOverride.ts

功能: 获取带活动覆盖信息的进程数据


88. useCustomRuleQuery - 自定义规则查询

位置: packages/console/src/hooks/useCustomRuleQuery.ts

功能: 管理自定义规则的查询条件


89. useDetectionSidepaneObjects - 检测 SidePane 对象

位置: packages/console/src/hooks/useDetectionSidepaneObjects.ts

功能: 获取检测 SidePane 的对象数据


90. useImageSbomDetails - 镜像 SBOM 详情

位置: packages/console/src/hooks/useImageSbomDetails.tsx

功能: 获取镜像的 SBOM(软件物料清单)详情


91. useApiVulnerabilityData - API 漏洞数据

位置: packages/console/src/hooks/UseApiVulnerabilityData.ts

功能: 获取 API 相关的漏洞数据


92. useEntitiesFilterCount - 实体过滤器计数

位置: packages/console/src/hooks/UseEntitiesFilterCount.ts

功能: 计算实体过滤器的匹配数量


93. useObjectsStorageWithFilters - 带过滤器的对象 Storage

位置: packages/console/src/hooks/UseObjectsStorageWithFilters.ts

功能: 获取带过滤器的对象 Storage


94. useArrayValues - 数组值

位置: packages/console/src/hooks/UseArrayValues.ts

功能: 管理数组值的状态


95. useActionSaveState - 操作保存状态

位置: packages/console/src/hooks/UseActionSaveState.ts

功能: 跟踪操作的保存状态


96. useActiveListItem - 活动列表项

位置: packages/console/src/hooks/UseActiveListItem.ts

功能: 管理列表中的活动项


97. useUsedDataModel - 使用的数据 Model

位置: packages/console/src/hooks/UseUsedDataModel.ts

功能: 获取当前使用的数据 Model


98. useUserSession - 用户会话

位置: packages/console/src/hooks/UseUserSession.ts

功能: 管理用户会话信息


99. useUpwindPageLayoutHeight - Upwind 页面布局高度

位置: packages/console/src/hooks/UseUpwindPageLayoutHeight.ts

功能: 计算和管理页面布局高度


100. useShortcutsPermissions - 快捷键权限

位置: packages/console/src/hooks/useShortcutsPermissions.ts

功能: 检查快捷键的权限


101. useScopeAttributeRenderer - 作用域属性渲染器

位置: packages/console/src/hooks/useScopeAttributeRenderer.tsx

功能: 渲染作用域相关的属性


102. useTabContentScroller - Tab 内容滚动器

位置: packages/console/src/hooks/useTabContentScroller.tsx

功能: 管理 Tab 内容的滚动行为


103. useTabContentDimensions - Tab 内容尺寸

位置: packages/console/src/hooks/useTabContentDimensions.ts

功能: 跟踪 Tab 内容的尺寸


104. useSmallNavBarFontSize - 小导航栏字体大小

位置: packages/console/src/hooks/useSmallNavBarFontSize.tsx

功能: 根据屏幕尺寸调整导航栏字体大小


105. useHighchartNavigatorMovement - Highchart 导航器移动

位置: packages/console/src/hooks/useHighchartNavigatorMovement.ts

功能: 处理 Highchart 图表的导航器移动事件


106. useOnShareFindingsEmailsClick - 分享发现邮件点击

位置: packages/console/src/hooks/useOnShareFindingsEmailsClick.tsx

功能: 处理分享发现邮件的点击事件


107. useIsNewJiraServiceFfOpen - 新 Jira 服务功能标志

位置: packages/console/src/hooks/useIsNewJiraServiceFfOpen.tsx

功能: 检查新 Jira 服务功能标志是否开启


108. useDspmFeatureGate - DSPM 功能门控

位置: packages/console/src/hooks/useDspmFeatureGate.tsx

功能: 检查 DSPM(数据安全态势管理)功能是否可用


109. useQueryPropertyUiConfigMap - 查询属性 UI 配置映射

位置: packages/console/src/hooks/useQueryPropertyUiConfigMap.ts

功能: 获取查询属性的 UI 配置映射


110. useAccountsWithNewOnBoardingConfig - 带新配置的账户

位置: packages/console/src/hooks/useAccountsWithNewOnBoardingConfig.ts

功能: 获取带有新配置的账户


111. useAccessManagementScopesAndRolesQuery - 访问管理作用域和角色查询

位置: packages/console/src/hooks/useAccessManagementScopesAndRolesQuery.ts

功能: 查询访问管理的作用域和角色


112. useElementSize - 元素尺寸(已在 Utility Hooks 说明)


113. useSshSessionObject - SSH 会话对象

位置: packages/console/src/hooks/UseSshSessionObject.ts

功能: 获取 SSH 会话对象


114. useInternetExposureObject - Internet 暴露对象

位置: packages/console/src/hooks/UseInternetExposureObject.ts

功能: 获取 Internet 暴露相关的对象


115. useStorage - Storage(通用)

位置: packages/console/src/hooks/UseStorage.ts

功能: 通用的 Storage Hook,支持多种 Storage 类型


十一、Hook 架构总结

架构层次

React Component LayerReact 组件层)
  ↓
Hooks LayerHook 层 - 本文档)
  ├─ DataStorage Hooks
  │   ├─ useDataStorageObject → DataStorage(事件驱动)
  │   ├─ useDataStorageObjects → DataStorage(事件驱动)
  │   └─ useDataStorageLoadingState → DataStorage.loadingObject
  │
  ├─ ObjectWithEvents Hooks
  │   ├─ useObjectAttribute → ObjectWithEvents(事件驱动)
  │   └─ useObjectAttributes → ObjectWithEvents(事件驱动)
  │
  ├─ Model Hooks
  │   ├─ useModel → PanesModels(注册表 + 引用计数)
  │   ├─ useSidePaneModel → useModel(SidePane 特定)
  │   ├─ useModelLoadingIdState → AbstractDataModel.loadingObject
  │   └─ useModelOrStorageLoadingState → Model/Storage.loadingObject
  │
  ├─ Router Hooks
  │   └─ useRouterAttribute → Router(事件驱动 + URL 同步)
  │
  ├─ Filter Hooks
  │   └─ useFilters → DataStorageWithFilters(事件驱动)
  │
  ├─ AsyncStorage Hooks
  │   └─ useAsyncStorageObject → AsyncStorage(懒加载)
  │
  ├─ Performance Hooks
  │   ├─ useDebounce → setTimeout
  │   └─ useMicroDebounceHandler → Promise.resolve()
  │
  └─ Utility Hooks
      ├─ useToggle → useState
      ├─ useControllableState → useState(受控/非受控)
      └─ useTheme → ThemeContextDataModel Layer(数据模型层)
  ├─ DataStorage(存储对象列表)
  ├─ ObjectWithEvents(存储状态对象)
  └─ AbstractDataModel(管理 storages + objects)
  ↓
Event System(事件系统)
  └─ EventEmitter(观察者模式)

核心设计模式

  1. 事件驱动架构:

    • 所有数据变化通过事件通知
    • Hook 订阅事件,自动更新 React state
    • 解耦数据层和 UI 层
  2. 观察者模式:

    • EventEmitter 实现观察者模式
    • Hook 是观察者,Storage/Model 是被观察者
    • 支持多个观察者订阅同一个事件
  3. 单一数据源:

    • Storage/Model 是唯一数据源
    • Hook 不存储数据,只同步状态
    • 确保数据一致性
  4. 自动同步机制:

    数据变化 → 触发事件 → Hook 回调 → 更新 React state → 组件重渲染
    
  5. 引用计数管理:

    • useModel 使用引用计数管理 Model 生命周期
    • 多个组件可以共享同一个 Model
    • 只有当所有组件卸载时,Model 才被清理
  6. 性能优化策略:

    • 微防抖:减少批量操作时的更新频率
    • 版本号检查:避免丢失外部更新
    • 深度比较:避免不必要的重渲染

Hook 使用最佳实践

  1. 选择合适的 Hook:

    • 单个对象 → useDataStorageObject
    • 对象列表 → useDataStorageObjects
    • 单个属性 → useObjectAttribute
    • 所有属性 → useObjectAttributes
    • 特定 ID 加载 → useModelLoadingIdState
    • 整体加载 → useModelOrStorageLoadingStateuseLoader
  2. 避免不必要的重渲染:

    • 使用 useMemo 缓存计算结果
    • 使用 useCallback 缓存回调函数
    • 避免在 Hook 中创建新对象
  3. 正确处理依赖:

    • 确保 useEffect 的依赖数组正确
    • 避免遗漏依赖导致 stale closure
  4. 清理资源:

    • useEffect 的清理函数中取消事件监听
    • 避免内存泄漏
  5. 错误处理:

    • 使用 useAsyncStorageObject 时处理错误状态
    • 使用 try-catch 包装异步操作

总结

本项目共有 115+ 个 Hook,分为 11 个主要类别:

  1. DataStorage Hooks(6个)- 核心数据层,事件驱动
  2. ObjectWithEvents Hooks(2个)- 状态对象层,事件驱动
  3. Model Loading Hooks(3个)- 加载状态管理
  4. Filter Hooks(1个)- 过滤器管理
  5. Router Hooks(1个)- 路由状态同步
  6. Model 管理 Hooks(2个)- Model 生命周期管理
  7. AsyncStorage Hooks(2个)- 异步数据加载
  8. 性能优化 Hooks(2个)- 防抖优化
  9. Utility Hooks(7个)- 通用工具
  10. Console 特定 Hooks(89个)- 业务特定功能
  11. 其他 Hooks(多个)- 各种辅助功能

所有 Hook 都遵循事件驱动的设计模式,通过 EventEmitter 实现数据层和 UI 层的解耦,确保数据变化能够自动同步到 React 组件。