diff --git a/libs/horizon/src/event/FormValueController.ts b/libs/horizon/src/event/FormValueController.ts index ac0603e8..3c63a299 100644 --- a/libs/horizon/src/event/FormValueController.ts +++ b/libs/horizon/src/event/FormValueController.ts @@ -37,35 +37,6 @@ export function shouldControlValue(): boolean { return changeEventTargets !== null && changeEventTargets.length > 0; } -// 从缓存队列中对受控组件进行赋值 -export function tryControlValue() { - if (!changeEventTargets) { - return; - } - changeEventTargets.forEach(target => { - controlValue(target); - }); - changeEventTargets = null; -} - -// 受控组件值重新赋值 -function controlValue(target: Element) { - const props = getVNodeProps(target); - if (props) { - const type = getDomTag(target); - switch (type) { - case 'input': - controlInputValue(target, props); - break; - case 'textarea': - updateTextareaValue(target, props); - break; - default: - break; - } - } -} - function controlInputValue(inputDom: HTMLInputElement, props: Props) { const { name, type } = props; @@ -87,3 +58,32 @@ function controlInputValue(inputDom: HTMLInputElement, props: Props) { updateInputValue(inputDom, props); } } + +// 受控组件值重新赋值 +function controlValue(target: Element) { + const props = getVNodeProps(target); + if (props) { + const type = getDomTag(target); + switch (type) { + case 'input': + controlInputValue(target, props); + break; + case 'textarea': + updateTextareaValue(target, props); + break; + default: + break; + } + } +} + +// 从缓存队列中对受控组件进行赋值 +export function tryControlValue() { + if (!changeEventTargets) { + return; + } + changeEventTargets.forEach(target => { + controlValue(target); + }); + changeEventTargets = null; +} diff --git a/libs/horizon/src/horizonx/adapters/redux.ts b/libs/horizon/src/horizonx/adapters/redux.ts index 03ad253b..97b7a483 100644 --- a/libs/horizon/src/horizonx/adapters/redux.ts +++ b/libs/horizon/src/horizonx/adapters/redux.ts @@ -54,15 +54,12 @@ export type ReduxMiddleware = ( type Reducer = (state: any, action: ReduxAction) => any; function mergeData(state, data) { - console.log('merging data', { state, data }); if (!data) { - console.log('!data'); state.stateWrapper = data; return; } if (Array.isArray(data) && Array.isArray(state?.stateWrapper)) { - console.log('data is array'); state.stateWrapper.length = data.length; data.forEach((item, idx) => { if (item != state.stateWrapper[idx]) { @@ -73,9 +70,10 @@ function mergeData(state, data) { } if (typeof data === 'object' && typeof state?.stateWrapper === 'object') { - console.log('data is object'); Object.keys(state.stateWrapper).forEach(key => { - if (!data.hasOwnProperty(key)) delete state.stateWrapper[key]; + if (!Object.prototype.hasOwnProperty.call(data, key)) { + delete state.stateWrapper[key]; + } }); Object.entries(data).forEach(([key, value]) => { @@ -86,7 +84,6 @@ function mergeData(state, data) { return; } - console.log('data is primitive or type mismatch'); state.stateWrapper = data; } @@ -106,7 +103,6 @@ export function createStore(reducer: Reducer, preloadedState?: any, enhancers?): if (result === undefined) { return; } // NOTE: reducer should never return undefined, in this case, do not change state - // mergeData(state,result); state.stateWrapper = result; }, }, @@ -115,10 +111,6 @@ export function createStore(reducer: Reducer, preloadedState?: any, enhancers?): }, })(); - // store.$subscribe(()=>{ - // console.log('changed'); - // }); - const result = { reducer, getState: function () { @@ -157,12 +149,6 @@ export function combineReducers(reducers: { [key: string]: Reducer }): Reducer { }; } -export function applyMiddleware(...middlewares: ReduxMiddleware[]): (store: ReduxStoreHandler) => void { - return store => { - return applyMiddlewares(store, middlewares); - }; -} - function applyMiddlewares(store: ReduxStoreHandler, middlewares: ReduxMiddleware[]): void { middlewares = middlewares.slice(); middlewares.reverse(); @@ -173,6 +159,12 @@ function applyMiddlewares(store: ReduxStoreHandler, middlewares: ReduxMiddleware store.dispatch = dispatch; } +export function applyMiddleware(...middlewares: ReduxMiddleware[]): (store: ReduxStoreHandler) => void { + return store => { + return applyMiddlewares(store, middlewares); + }; +} + type ActionCreator = (...params: any[]) => ReduxAction; type ActionCreators = { [key: string]: ActionCreator }; export type BoundActionCreator = (...params: any[]) => void; diff --git a/libs/horizon/src/renderer/hooks/HookMain.ts b/libs/horizon/src/renderer/hooks/HookMain.ts index 31a5be53..f22376f3 100644 --- a/libs/horizon/src/renderer/hooks/HookMain.ts +++ b/libs/horizon/src/renderer/hooks/HookMain.ts @@ -18,6 +18,12 @@ import type { VNode } from '../Types'; import { getLastTimeHook, setLastTimeHook, setCurrentHook, getNextHook } from './BaseHook'; import { HookStage, setHookStage } from './HookStage'; +function resetGlobalVariable() { + setHookStage(null); + setLastTimeHook(null); + setCurrentHook(null); +} + // hook对外入口 export function runFunctionWithHooks, Arg>( funcComp: (props: Props, arg: Arg) => any, @@ -57,9 +63,3 @@ export function runFunctionWithHooks, Arg>( return comp; } - -function resetGlobalVariable() { - setHookStage(null); - setLastTimeHook(null); - setCurrentHook(null); -} diff --git a/libs/horizon/src/renderer/hooks/UseEffectHook.ts b/libs/horizon/src/renderer/hooks/UseEffectHook.ts index cd8e4313..9d11c01d 100644 --- a/libs/horizon/src/renderer/hooks/UseEffectHook.ts +++ b/libs/horizon/src/renderer/hooks/UseEffectHook.ts @@ -21,27 +21,17 @@ import { getHookStage, HookStage } from './HookStage'; import { isArrayEqual } from '../utils/compare'; import { getProcessingVNode } from '../GlobalVar'; -export function useEffectImpl(effectFunc: () => (() => void) | void, deps?: Array | null): void { - // 异步触发的effect - useEffect(effectFunc, deps, EffectConstant.Effect); -} +function createEffect(effectFunc, removeFunc, deps, effectConstant): Effect { + const effect: Effect = { + effect: effectFunc, + removeEffect: removeFunc, + dependencies: deps, + effectConstant: effectConstant, + }; -export function useLayoutEffectImpl(effectFunc: () => (() => void) | void, deps?: Array | null): void { - // 同步触发的effect - useEffect(effectFunc, deps, EffectConstant.LayoutEffect); -} + getProcessingVNode().effectList.push(effect); -function useEffect(effectFunc: () => (() => void) | void, deps: Array | void | null, effectType: number): void { - const stage = getHookStage(); - if (stage === null) { - throwNotInFuncError(); - } - - if (stage === HookStage.Init) { - useEffectForInit(effectFunc, deps, effectType); - } else if (stage === HookStage.Update) { - useEffectForUpdate(effectFunc, deps, effectType); - } + return effect; } export function useEffectForInit(effectFunc, deps, effectType): void { @@ -76,15 +66,25 @@ export function useEffectForUpdate(effectFunc, deps, effectType): void { hook.state = createEffect(effectFunc, removeFunc, nextDeps, EffectConstant.DepsChange | effectType); } -function createEffect(effectFunc, removeFunc, deps, effectConstant): Effect { - const effect: Effect = { - effect: effectFunc, - removeEffect: removeFunc, - dependencies: deps, - effectConstant: effectConstant, - }; +function useEffect(effectFunc: () => (() => void) | void, deps: Array | void | null, effectType: number): void { + const stage = getHookStage(); + if (stage === null) { + throwNotInFuncError(); + } - getProcessingVNode().effectList.push(effect); - - return effect; + if (stage === HookStage.Init) { + useEffectForInit(effectFunc, deps, effectType); + } else if (stage === HookStage.Update) { + useEffectForUpdate(effectFunc, deps, effectType); + } +} + +export function useEffectImpl(effectFunc: () => (() => void) | void, deps?: Array | null): void { + // 异步触发的effect + useEffect(effectFunc, deps, EffectConstant.Effect); +} + +export function useLayoutEffectImpl(effectFunc: () => (() => void) | void, deps?: Array | null): void { + // 同步触发的effect + useEffect(effectFunc, deps, EffectConstant.LayoutEffect); } diff --git a/libs/horizon/src/renderer/hooks/UseImperativeHook.ts b/libs/horizon/src/renderer/hooks/UseImperativeHook.ts index b9f6d581..3ae2feef 100644 --- a/libs/horizon/src/renderer/hooks/UseImperativeHook.ts +++ b/libs/horizon/src/renderer/hooks/UseImperativeHook.ts @@ -18,20 +18,6 @@ import { getHookStage } from './HookStage'; import { throwNotInFuncError } from './BaseHook'; import type { Ref } from './HookType'; -export function useImperativeHandleImpl( - ref: { current: R | null } | ((any) => any) | null | void, - func: () => R, - dependencies?: Array | null -): void { - const stage = getHookStage(); - if (stage === null) { - throwNotInFuncError(); - } - - const params = isNotNull(dependencies) ? dependencies.concat([ref]) : null; - useLayoutEffectImpl(effectFunc.bind(null, func, ref), params); -} - function isNotNull(object: any): boolean { return object !== null && object !== undefined; } @@ -52,3 +38,17 @@ function effectFunc(func: () => R, ref: Ref | ((any) => any) | null): (() }; } } + +export function useImperativeHandleImpl( + ref: { current: R | null } | ((any) => any) | null | void, + func: () => R, + dependencies?: Array | null +): void { + const stage = getHookStage(); + if (stage === null) { + throwNotInFuncError(); + } + + const params = isNotNull(dependencies) ? dependencies.concat([ref]) : null; + useLayoutEffectImpl(effectFunc.bind(null, func, ref), params); +} diff --git a/libs/horizon/src/renderer/hooks/UseReducerHook.ts b/libs/horizon/src/renderer/hooks/UseReducerHook.ts index 3637f775..86572fb7 100644 --- a/libs/horizon/src/renderer/hooks/UseReducerHook.ts +++ b/libs/horizon/src/renderer/hooks/UseReducerHook.ts @@ -22,29 +22,6 @@ import { getHookStage, HookStage } from './HookStage'; import type { VNode } from '../Types'; import { getProcessingVNode } from '../GlobalVar'; -export function useReducerImpl( - reducer: (S, A) => S, - initArg: P, - init?: (P) => S, - isUseState?: boolean -): [S, Trigger] | void { - const stage = getHookStage(); - if (stage === null) { - throwNotInFuncError(); - } - - if (stage === HookStage.Init) { - return useReducerForInit(reducer, initArg, init, isUseState); - } else if (stage === HookStage.Update) { - // 获取当前的hook - const currentHook = getCurrentHook(); - // 获取currentHook的更新数组 - const currentHookUpdates = (currentHook.state as Reducer).updates; - - return updateReducerHookState(currentHookUpdates, currentHook, reducer); - } -} - // 构造新的Update数组 function insertUpdate(action: A, hook: Hook): Update { const newUpdate: Update = { @@ -116,6 +93,25 @@ export function useReducerForInit(reducer, initArg, init, isUseState?: boo return [hook.state.stateValue, trigger]; } +// 计算stateValue值 +function calculateNewState(currentHookUpdates: Array>, currentHook, reducer: (S, A) => S) { + const reducerObj = currentHook.state; + let state = reducerObj.stateValue; + + // 循环遍历更新数组,计算新的状态值 + currentHookUpdates.forEach(update => { + // 1. didCalculated = true 说明state已经计算过; 2. 如果来自 isUseState + if (update.didCalculated && reducerObj.isUseState) { + state = update.state; + } else { + const action = update.action; + state = reducer(state, action); + } + }); + + return state; +} + // 更新hook.state function updateReducerHookState(currentHookUpdates, currentHook, reducer): [S, Trigger] { if (currentHookUpdates !== null) { @@ -135,21 +131,25 @@ function updateReducerHookState(currentHookUpdates, currentHook, reducer): return [currentHook.state.stateValue, currentHook.state.trigger]; } -// 计算stateValue值 -function calculateNewState(currentHookUpdates: Array>, currentHook, reducer: (S, A) => S) { - const reducerObj = currentHook.state; - let state = reducerObj.stateValue; +export function useReducerImpl( + reducer: (S, A) => S, + initArg: P, + init?: (P) => S, + isUseState?: boolean +): [S, Trigger] | void { + const stage = getHookStage(); + if (stage === null) { + throwNotInFuncError(); + } - // 循环遍历更新数组,计算新的状态值 - currentHookUpdates.forEach(update => { - // 1. didCalculated = true 说明state已经计算过; 2. 如果来自 isUseState - if (update.didCalculated && reducerObj.isUseState) { - state = update.state; - } else { - const action = update.action; - state = reducer(state, action); - } - }); + if (stage === HookStage.Init) { + return useReducerForInit(reducer, initArg, init, isUseState); + } else if (stage === HookStage.Update) { + // 获取当前的hook + const currentHook = getCurrentHook(); + // 获取currentHook的更新数组 + const currentHookUpdates = (currentHook.state as Reducer).updates; - return state; + return updateReducerHookState(currentHookUpdates, currentHook, reducer); + } } diff --git a/libs/horizon/src/renderer/submit/HookEffectHandler.ts b/libs/horizon/src/renderer/submit/HookEffectHandler.ts index c7db9c32..06bfd371 100644 --- a/libs/horizon/src/renderer/submit/HookEffectHandler.ts +++ b/libs/horizon/src/renderer/submit/HookEffectHandler.ts @@ -40,28 +40,6 @@ export function isSchedulingEffects() { return isScheduling; } -export function callUseEffects(vNode: VNode) { - const effectList: EffectList = vNode.effectList; - if (effectList !== null) { - effectList.forEach(effect => { - const { effectConstant } = effect; - if ( - (effectConstant & EffectConstant.Effect) !== EffectConstant.NoEffect && - (effectConstant & EffectConstant.DepsChange) !== EffectConstant.NoEffect - ) { - hookEffects.push(effect); - hookRemoveEffects.push(effect); - - // 异步调用 - if (!isScheduling) { - isScheduling = true; - runAsync(runAsyncEffects); - } - } - }); - } -} - export function runAsyncEffects() { const preMode = copyExecuteMode(); changeMode(InRender, true); @@ -98,6 +76,28 @@ export function runAsyncEffects() { setExecuteMode(preMode); } +export function callUseEffects(vNode: VNode) { + const effectList: EffectList = vNode.effectList; + if (effectList !== null) { + effectList.forEach(effect => { + const { effectConstant } = effect; + if ( + (effectConstant & EffectConstant.Effect) !== EffectConstant.NoEffect && + (effectConstant & EffectConstant.DepsChange) !== EffectConstant.NoEffect + ) { + hookEffects.push(effect); + hookRemoveEffects.push(effect); + + // 异步调用 + if (!isScheduling) { + isScheduling = true; + runAsync(runAsyncEffects); + } + } + }); + } +} + // 在销毁vNode的时候调用remove export function callEffectRemove(vNode: VNode) { const effectList: EffectList = vNode.effectList; diff --git a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts index cd3461b2..ebf73031 100644 --- a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts +++ b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts @@ -154,18 +154,6 @@ function hideOrUnhideAllChildren(vNode, isHidden) { ); } -function attachRef(vNode: VNode) { - const ref = vNode.ref; - - handleRef(vNode, ref, vNode.realNode); -} - -function detachRef(vNode: VNode, isOldRef?: boolean) { - const ref = isOldRef ? vNode.oldRef : vNode.ref; - - handleRef(vNode, ref, null); -} - function handleRef(vNode: VNode, ref, val) { if (ref !== null && ref !== undefined) { const refType = typeof ref; @@ -182,6 +170,18 @@ function handleRef(vNode: VNode, ref, val) { } } +function attachRef(vNode: VNode) { + const ref = vNode.ref; + + handleRef(vNode, ref, vNode.realNode); +} + +function detachRef(vNode: VNode, isOldRef?: boolean) { + const ref = isOldRef ? vNode.oldRef : vNode.ref; + + handleRef(vNode, ref, null); +} + // 卸载一个vNode,不会递归 function unmountVNode(vNode: VNode): void { switch (vNode.tag) { @@ -217,6 +217,9 @@ function unmountVNode(vNode: VNode): void { unmountDomComponents(vNode); break; } + default: { + break; + } } } @@ -413,6 +416,9 @@ function submitUpdate(vNode: VNode): void { listenToPromise(vNode); break; } + default: { + break; + } } } diff --git a/libs/horizon/src/renderer/submit/Submit.ts b/libs/horizon/src/renderer/submit/Submit.ts index 4ea6d47c..f0e8982a 100644 --- a/libs/horizon/src/renderer/submit/Submit.ts +++ b/libs/horizon/src/renderer/submit/Submit.ts @@ -41,63 +41,6 @@ const LOOPING_UPDATE_LIMIT = 50; let loopingUpdateCount = 0; let lastRoot: VNode | null = null; -export function submitToRender(treeRoot) { - treeRoot.shouldUpdate = treeRoot.childShouldUpdate; - // 置空task,让才能加入新的render任务 - treeRoot.task = null; - - const startVNode = getStartVNode(); - - if (FlagUtils.hasAnyFlag(startVNode)) { - // 把自己加上 - if (startVNode.dirtyNodes === null) { - startVNode.dirtyNodes = [startVNode]; - } else { - startVNode.dirtyNodes.push(startVNode); - } - } - - const dirtyNodes = startVNode.dirtyNodes; - if (dirtyNodes !== null && dirtyNodes.length) { - const preMode = copyExecuteMode(); - changeMode(InRender, true); - - prepareForSubmit(); - // before submit阶段 - beforeSubmit(dirtyNodes); - - // submit阶段 - submit(dirtyNodes); - - resetAfterSubmit(); - - // after submit阶段 - afterSubmit(dirtyNodes); - - setExecuteMode(preMode); - dirtyNodes.length = 0; - startVNode.dirtyNodes = null; - } - - if (isSchedulingEffects()) { - setSchedulingEffects(false); - } - - // 统计root同步重渲染的次数,如果太多可能是无线循环 - countLoopingUpdate(treeRoot); - - // 在退出`submit` 之前始终调用此函数,以确保任何已计划在此根上执行的update被执行。 - tryRenderFromRoot(treeRoot); - - if (rootThrowError) { - const error = rootThrowError; - rootThrowError = null; - throw error; - } - - return null; -} - function beforeSubmit(dirtyNodes: Array) { let node; const nodesLength = dirtyNodes.length; @@ -214,3 +157,60 @@ export function checkLoopingUpdateLimit() { ); } } + +export function submitToRender(treeRoot) { + treeRoot.shouldUpdate = treeRoot.childShouldUpdate; + // 置空task,让才能加入新的render任务 + treeRoot.task = null; + + const startVNode = getStartVNode(); + + if (FlagUtils.hasAnyFlag(startVNode)) { + // 把自己加上 + if (startVNode.dirtyNodes === null) { + startVNode.dirtyNodes = [startVNode]; + } else { + startVNode.dirtyNodes.push(startVNode); + } + } + + const dirtyNodes = startVNode.dirtyNodes; + if (dirtyNodes !== null && dirtyNodes.length) { + const preMode = copyExecuteMode(); + changeMode(InRender, true); + + prepareForSubmit(); + // before submit阶段 + beforeSubmit(dirtyNodes); + + // submit阶段 + submit(dirtyNodes); + + resetAfterSubmit(); + + // after submit阶段 + afterSubmit(dirtyNodes); + + setExecuteMode(preMode); + dirtyNodes.length = 0; + startVNode.dirtyNodes = null; + } + + if (isSchedulingEffects()) { + setSchedulingEffects(false); + } + + // 统计root同步重渲染的次数,如果太多可能是无线循环 + countLoopingUpdate(treeRoot); + + // 在退出`submit` 之前始终调用此函数,以确保任何已计划在此根上执行的update被执行。 + tryRenderFromRoot(treeRoot); + + if (rootThrowError) { + const error = rootThrowError; + rootThrowError = null; + throw error; + } + + return null; +} diff --git a/libs/horizon/src/renderer/taskExecutor/BrowserAsync.ts b/libs/horizon/src/renderer/taskExecutor/BrowserAsync.ts index 6da28613..cccef59d 100644 --- a/libs/horizon/src/renderer/taskExecutor/BrowserAsync.ts +++ b/libs/horizon/src/renderer/taskExecutor/BrowserAsync.ts @@ -27,6 +27,14 @@ export function isOverTime() { return false; } +function asyncCall() { + if (isTestRuntime) { + setTimeout(callRenderTasks, 0); + } else { + port2.postMessage(null); + } +} + // 1、设置deadline;2、回调TaskExecutor传过来的browserCallback const callRenderTasks = () => { if (browserCallback === null) { @@ -61,14 +69,6 @@ if (typeof MessageChannel === 'function') { isTestRuntime = true; } -function asyncCall() { - if (isTestRuntime) { - setTimeout(callRenderTasks, 0); - } else { - port2.postMessage(null); - } -} - export function requestBrowserCallback(callback) { browserCallback = callback; diff --git a/libs/horizon/src/renderer/taskExecutor/RenderQueue.ts b/libs/horizon/src/renderer/taskExecutor/RenderQueue.ts index 0fe3e533..729dfbc8 100644 --- a/libs/horizon/src/renderer/taskExecutor/RenderQueue.ts +++ b/libs/horizon/src/renderer/taskExecutor/RenderQueue.ts @@ -27,16 +27,6 @@ let callingQueueTask: any | null = null; // 防止重入 let isCallingRenderQueue = false; -export function callRenderQueueImmediate() { - if (callingQueueTask !== null) { - // 取消异步调度 - cancelTask(callingQueueTask); - callingQueueTask = null; - } - - callRenderQueue(); -} - // 执行render回调 function callRenderQueue() { if (!isCallingRenderQueue && renderQueue !== null) { @@ -58,6 +48,16 @@ function callRenderQueue() { } } +export function callRenderQueueImmediate() { + if (callingQueueTask !== null) { + // 取消异步调度 + cancelTask(callingQueueTask); + callingQueueTask = null; + } + + callRenderQueue(); +} + export function pushRenderCallback(callback: RenderCallback) { if (renderQueue === null) { renderQueue = [callback]; diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index 4214e928..40ba0554 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -200,6 +200,8 @@ export class VNode { break; case Profiler: break; + default: + break; } } } diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts index 6b96e49e..73944854 100644 --- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts +++ b/libs/horizon/src/renderer/vnode/VNodeCreator.ts @@ -194,6 +194,8 @@ export function createVNode(tag: VNodeTag | string, ...secondArg) { vNode.updates = []; break; + default: + break; } return vNode; diff --git a/libs/horizon/src/renderer/vnode/VNodeUtils.ts b/libs/horizon/src/renderer/vnode/VNodeUtils.ts index 7e55f48d..d9bb0f50 100644 --- a/libs/horizon/src/renderer/vnode/VNodeUtils.ts +++ b/libs/horizon/src/renderer/vnode/VNodeUtils.ts @@ -169,13 +169,6 @@ export function findDOMByClassInst(inst) { return domVNode !== null ? domVNode.realNode : null; } -// 判断dom树是否已经挂载 -export function isMounted(vNode: VNode) { - const rootNode = getTreeRootVNode(vNode); - // 如果根节点是 Dom 类型节点,表示已经挂载 - return rootNode.tag === TreeRoot; -} - function getTreeRootVNode(vNode) { let node = vNode; while (node.parent) { @@ -184,6 +177,13 @@ function getTreeRootVNode(vNode) { return node; } +// 判断dom树是否已经挂载 +export function isMounted(vNode: VNode) { + const rootNode = getTreeRootVNode(vNode); + // 如果根节点是 Dom 类型节点,表示已经挂载 + return rootNode.tag === TreeRoot; +} + // 找到相邻的DOM export function getSiblingDom(vNode: VNode): Element | null { let node: VNode = vNode;