From 2ba2d78d4f5781bff0c89ee0f4f69c84c1edbcd0 Mon Sep 17 00:00:00 2001
From: * <8>
Date: Thu, 7 Jul 2022 16:57:14 +0800
Subject: [PATCH] Match-id-99816485a3994e661f2c58e75d8f852e44192ecc
---
libs/horizon/src/renderer/ContextSaver.ts | 19 ++++-
libs/horizon/src/renderer/TreeBuilder.ts | 6 +-
.../__tests__/ComponentTest/Context.test.js | 75 +++++++++++++++++++
3 files changed, 97 insertions(+), 3 deletions(-)
diff --git a/libs/horizon/src/renderer/ContextSaver.ts b/libs/horizon/src/renderer/ContextSaver.ts
index cd21da0b..2e72ce3c 100644
--- a/libs/horizon/src/renderer/ContextSaver.ts
+++ b/libs/horizon/src/renderer/ContextSaver.ts
@@ -45,13 +45,28 @@ export function resetContext(providerVNode: VNode) {
context.value = providerVNode.context;
}
-// 在局部更新时,恢复父节点的context
+// 在局部更新时,从上到下恢复父节点的context
export function recoverParentContext(vNode: VNode) {
+ const contextProviders: VNode[] = [];
+ let parent = vNode.parent;
+ while (parent !== null) {
+ if (parent.tag === ContextProvider) {
+ contextProviders.unshift(parent);
+ }
+ parent = parent.parent;
+ }
+ contextProviders.forEach(node => {
+ setContext(node, node.props.value);
+ });
+}
+
+// 在局部更新时,从下到上重置父节点的context
+export function resetParentContext(vNode: VNode) {
let parent = vNode.parent;
while (parent !== null) {
if (parent.tag === ContextProvider) {
- setContext(parent, parent.props.value);
+ resetContext(parent);
}
parent = parent.parent;
}
diff --git a/libs/horizon/src/renderer/TreeBuilder.ts b/libs/horizon/src/renderer/TreeBuilder.ts
index 32bc6c14..c8b81ae7 100644
--- a/libs/horizon/src/renderer/TreeBuilder.ts
+++ b/libs/horizon/src/renderer/TreeBuilder.ts
@@ -29,7 +29,7 @@ import {
isExecuting,
setExecuteMode
} from './ExecuteMode';
-import { recoverParentContext, resetNamespaceCtx, setNamespaceCtx } from './ContextSaver';
+import { recoverParentContext, resetParentContext, resetNamespaceCtx, setNamespaceCtx } from './ContextSaver';
import {
updateChildShouldUpdate,
updateParentsChildShouldUpdate,
@@ -263,6 +263,10 @@ function buildVNodeTree(treeRoot: VNode) {
handleError(treeRoot, thrownValue);
}
}
+ if (startVNode.tag !== TreeRoot) { // 不是根节点
+ // 恢复父节点的context
+ resetParentContext(startVNode);
+ }
setProcessingClassVNode(null);
diff --git a/scripts/__tests__/ComponentTest/Context.test.js b/scripts/__tests__/ComponentTest/Context.test.js
index d64934ef..14423b34 100644
--- a/scripts/__tests__/ComponentTest/Context.test.js
+++ b/scripts/__tests__/ComponentTest/Context.test.js
@@ -358,4 +358,79 @@ describe('Context Test', () => {
Horizon.render(, container);
expect(container.querySelector('p').innerHTML).toBe('Num: 8, Type: typeR');
});
+
+ // antd menu 级连context场景,menu路径使用级联context实现
+ it('nested context', () => {
+ const NestedContext = Horizon.createContext([]);
+ let updateContext;
+
+ function App() {
+ const [state, useState] = Horizon.useState([]);
+ updateContext = useState;
+ return (
+
+
+
+
+ );
+ }
+
+ const div1Ref = Horizon.createRef();
+ const div2Ref = Horizon.createRef();
+
+ let updateSub1;
+ function Sub1() {
+ const path = Horizon.useContext(NestedContext);
+ const [_, setState] = Horizon.useState({});
+ updateSub1 = () => setState({});
+ return (
+
+
+
+ );
+ }
+
+ function Sub2() {
+ const path = Horizon.useContext(NestedContext);
+
+ return (
+
+
+
+ );
+ }
+
+ function Sub3() {
+ const path = Horizon.useContext(NestedContext);
+
+ return (
+
+
+
+ );
+ }
+
+ function Son({ divRef }) {
+ const path = Horizon.useContext(NestedContext);
+ return (
+
+ {path.join(',')}
+
+ );
+ }
+
+ Horizon.render(, container);
+ updateSub1();
+ expect(div1Ref.current.innerHTML).toEqual('1');
+ expect(div2Ref.current.innerHTML).toEqual('2,3');
+
+ updateContext([0]);
+ expect(div1Ref.current.innerHTML).toEqual('0,1');
+ expect(div2Ref.current.innerHTML).toEqual('0,2,3');
+
+ // 局部更新Sub1
+ updateSub1();
+ expect(div1Ref.current.innerHTML).toEqual('0,1');
+ expect(div2Ref.current.innerHTML).toEqual('0,2,3');
+ });
});