From 004376160984c5700b25a9b46bd5a1a7a7490fb3 Mon Sep 17 00:00:00 2001 From: * <8> Date: Wed, 27 Apr 2022 10:32:19 +0800 Subject: [PATCH] Match-id-06a032e63a37a939ac11e0d3f94647bd2122360c --- libs/extension/readme.md | 22 ++++++++++++++++++---- libs/extension/src/parser/parseAttr.ts | 21 +++++++++++++-------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/libs/extension/readme.md b/libs/extension/readme.md index b54fecf2..d725a5f8 100644 --- a/libs/extension/readme.md +++ b/libs/extension/readme.md @@ -47,6 +47,9 @@ sequenceDiagram ``` ## 传输数据结构 +**限制:chrome.runtime.sendMessage只能传递 JSON-serializable 数据** + + ```ts type passData = { type: 'HORIZON_DEV_TOOLS', @@ -58,11 +61,22 @@ type passData = { ``` ## horizon和devTools的主要交互 -- 页面初始渲染 -- 页面更新 -- 页面销毁 +- App初始渲染 +- App更新 +- App销毁 +- 整个页面刷新 - devTools触发组件属性更新 +## 对 hook 类型的判断和值的获取 +Horizon 是一个底层框架,在 Horizon 与插件的交互过程中,我们不希望 Horizon 额外的增加一些代码和接口给插件使用,这可能会影响到 Horizon 的性能。 +所以我们决定直接感知 hook 的属性值,通过其属性值判断 hook 类型,并直接调用 Reducer 的 trigger 函数触发更新。 + +## 触发组件更新方式 +- 类组件的state:调用实例的 setState 函数触发更新 +- 类组件的props:浅复制props后更新props值并调用 forceUpdate 触发更新 +- 函数组件的props: +- 函数组件的state:调用 useState 函数触发更新 + ## VNode的清理 全局 hook 中保存了root VNode,在解析 VNode 树的时候也会保存 VNode 的引用,在清理VNode的时候这些 VNode 的引用也需要删除。 @@ -73,7 +87,7 @@ type passData = { - 通过解析 path 值可以分析出组件树的结构 ## 组件props/state/hook等数据的传输和解析 -将数据格式进行转换后进行传递。对于 props 和 类组件的 state,他们都是对象,可以将对象进行解析然后以 k-v 的形式,树的结构显示。函数组件的 Hooks 是以数组的形式存储在 vNode 的属性中的,每个 hook 的唯一标识符是 hIndex 属性值,在对象展示的时候不能展示该属性值,需要根据 hook 类型展示一个 state/ref/effect 等值。hook 中存储的值也可能不是对象,只是一个简单的字符串,他们的解析和 props/state 的解析同样存在差异。 +将数据格式进行转换后进行传递。对于 props 和 类组件的 state,他们都是对象,可以将对象进行解析然后以 k-v 的形式,树的结构显示。函数组件的 Hooks 是以数组的形式存储在 vNode 的属性中的,每个 hook 的唯一标识符是 hIndex 属性值,在对象展示的时候不能展示该属性值,需要根据 hook 类型展示一个 state/ref/effect 等值。hook 中存储的值也可能不是对象,只是一个简单的字符串或者 dom 元素,他们的解析和 props/state 的解析同样存在差异,需要单独处理。 ## 滚动动态渲染 Tree diff --git a/libs/extension/src/parser/parseAttr.ts b/libs/extension/src/parser/parseAttr.ts index 38238eda..652593db 100644 --- a/libs/extension/src/parser/parseAttr.ts +++ b/libs/extension/src/parser/parseAttr.ts @@ -99,7 +99,7 @@ const parseSubAttr = ( value, indentation: parentIndentation + 1, }; - if (hIndex) { + if (hIndex !== undefined) { item.hIndex = hIndex; } result.push(item); @@ -123,13 +123,18 @@ export function parseHooks(hooks: Hook[]) { const result: IAttr[] = []; const indentation = 0; hooks.forEach(hook => { - const { hIndex, state ,type } = hook; - if (type === 'useState') { - parseSubAttr((state as Reducer).stateValue, indentation, 'state', result, hIndex); - } else if (type === 'useRef') { + const { hIndex, state } = hook; + // 不同 hook 的 state 有不同属性,根据是否存在该属性判断 hook 类型 + // 采用这种方式是因为要拿到需要的属性值,和后续触发更新,必然要感知 hook 的属性值 + // 既然已经感知了属性,就不额外添加属性进行类型判断了 + if ((state as Reducer).stateValue) { + if ((state as Reducer).isUseState) { + parseSubAttr((state as Reducer).stateValue, indentation, 'state', result, hIndex); + } else { + parseSubAttr((state as Reducer).stateValue, indentation, 'reducer', result, hIndex); + } + } else if ((state as Ref).current) { parseSubAttr((state as Ref).current, indentation, 'ref', result, hIndex); - } else if (type === 'useReducer') { - parseSubAttr((state as Reducer).stateValue, indentation, 'reducer', result, hIndex); } }); return result; @@ -179,9 +184,9 @@ export function buildAttrModifyData(parsedAttrsType: string, attrs: IAttr[], val type = ModifyProps; } else if (parsedAttrsType === 'parsedState') { type = ModifyState; - path[0] = item.hIndex; } else if (parsedAttrsType === 'parsedHooks') { type = ModifyHooks; + path[0] = item.hIndex; } else { return null; }