From 0cf368c45d0c66fd9314c3d81dbcb2ee5d05b13e Mon Sep 17 00:00:00 2001 From: MrWangJustToDo <2711470541@qq.com> Date: Sun, 7 Jan 2024 15:21:13 +0800 Subject: [PATCH] improve flow --- .../src/client/renderDispatch/lazy.ts | 6 +- .../src/client/renderPlatform/feature.ts | 1 + .../myreact-dom/src/client/tools/highlight.ts | 216 ++++++++++-------- .../src/server/renderPlatform/feature.ts | 2 + .../src/reactive/feature.ts | 12 +- .../src/dispatchContext/feature.ts | 137 ++++++++--- .../src/dispatchQueue/feature.ts | 70 +++++- .../src/dispatchUpdate/feature.ts | 2 - .../src/processState/feature.ts | 16 +- .../src/renderDispatch/instance.ts | 3 - .../src/renderDispatch/interface.ts | 2 - .../src/renderPlatform/instance.ts | 10 +- .../src/renderUpdate/trigger.ts | 4 +- .../src/runtimeComponent/feature.ts | 12 +- .../src/runtimeFiber/instance.ts | 16 +- .../src/runtimeFiber/update.ts | 7 +- .../src/runtimeHook/create.ts | 15 +- .../src/runtimeHook/effect.ts | 24 +- .../src/runtimeHook/instance.ts | 10 +- .../src/runtimeHook/update.ts | 6 +- packages/myreact-shared/src/listTree.ts | 2 +- .../myreact-shared/src/symbol/fiberMode.ts | 4 + .../myreact-shared/src/symbol/fiberPatch.ts | 11 +- packages/myreact-shared/src/symbol/index.ts | 1 + .../myreact-shared/src/symbol/queueType.ts | 2 + packages/myreact/src/component/instance.ts | 6 +- packages/myreact/src/element/feature.ts | 4 + packages/myreact/src/internal/instance.ts | 4 +- packages/myreact/src/renderFiber/interface.ts | 4 +- .../myreact/src/renderPlatform/interface.ts | 1 + packages/myreact/src/renderQueue/interface.ts | 30 ++- packages/myreact/src/share/env.ts | 4 +- packages/myreact/src/share/index.ts | 1 + packages/myreact/src/share/lazy.ts | 22 ++ ui/ssr-example/src/client/app.tsx | 2 +- 35 files changed, 453 insertions(+), 216 deletions(-) create mode 100644 packages/myreact-shared/src/symbol/fiberMode.ts create mode 100644 packages/myreact/src/share/lazy.ts diff --git a/packages/myreact-dom/src/client/renderDispatch/lazy.ts b/packages/myreact-dom/src/client/renderDispatch/lazy.ts index 9c5bf58f..d8a0c60b 100644 --- a/packages/myreact-dom/src/client/renderDispatch/lazy.ts +++ b/packages/myreact-dom/src/client/renderDispatch/lazy.ts @@ -1,6 +1,6 @@ import { __my_react_internal__, createElement } from "@my-react/react"; import { devWarnWithFiber, WrapperByScope } from "@my-react/react-reconciler"; -import { isPromise, ListTree, STATE_TYPE } from "@my-react/react-shared"; +import { isPromise, ListTree } from "@my-react/react-shared"; import type { ClientDomDispatch } from "./instance"; import type { lazy, MixinMyReactFunctionComponent } from "@my-react/react"; @@ -26,7 +26,7 @@ const loadLazy = async (fiber: MyReactFiberNode, typedElementType: ReturnType["render"]; - fiber._update(STATE_TYPE.__triggerSync__); + typedElementType._update(fiber, typedElementType.render); } catch (e) { currentRenderPlatform.current.dispatchError({ fiber, error: e }); } finally { @@ -43,7 +43,7 @@ export const resolveLazyElementLegacy = (_fiber: MyReactFiberNode, _dispatch: Cl if (typedElementType._loaded === true) { if (_dispatch.isHydrateRender) { Promise.resolve().then(() => { - _fiber._update(STATE_TYPE.__triggerSync__); + typedElementType._update(_fiber, typedElementType.render); }); return WrapperByScope(_dispatch.resolveSuspense(_fiber)); } else { diff --git a/packages/myreact-dom/src/client/renderPlatform/feature.ts b/packages/myreact-dom/src/client/renderPlatform/feature.ts index a3e256dc..7e5664b3 100644 --- a/packages/myreact-dom/src/client/renderPlatform/feature.ts +++ b/packages/myreact-dom/src/client/renderPlatform/feature.ts @@ -26,6 +26,7 @@ function dispatchError(this: DomPlatform, _params: { fiber: MyReactFiberNode; er }); }); } + return void 0; } /** diff --git a/packages/myreact-dom/src/client/tools/highlight.ts b/packages/myreact-dom/src/client/tools/highlight.ts index 13cba7db..002becdc 100644 --- a/packages/myreact-dom/src/client/tools/highlight.ts +++ b/packages/myreact-dom/src/client/tools/highlight.ts @@ -112,31 +112,35 @@ export class HighLight { allPendingUpdate.forEach((fiber) => { if (include(fiber.state, STATE_TYPE.__unmount__)) return; - const node = fiber.nativeNode as HTMLElement; - if (node.nodeType === Node.TEXT_NODE) { - this.range.selectNodeContents(node); - } else { - this.range.selectNode(node); - } - const rect = this.range.getBoundingClientRect(); - if ( - (rect.width || rect.height) && - rect.top >= 0 && - rect.left >= 0 && - rect.right <= (window.innerWidth || document.documentElement.clientWidth) && - rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) - ) { - // do the highlight paint - const left = rect.left - 0.5; - const top = rect.top - 0.5; - const width = rect.width + 1; - const height = rect.height + 1; - context.strokeRect( - left < 0 ? 0 : left, - top < 0 ? 0 : top, - width > window.innerWidth ? window.innerWidth : width, - height > window.innerHeight ? window.innerHeight : height - ); + try { + const node = fiber.nativeNode as HTMLElement; + if (node.nodeType === Node.TEXT_NODE) { + this.range.selectNodeContents(node); + } else { + this.range.selectNode(node); + } + const rect = this.range.getBoundingClientRect(); + if ( + (rect.width || rect.height) && + rect.top >= 0 && + rect.left >= 0 && + rect.right <= (window.innerWidth || document.documentElement.clientWidth) && + rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) + ) { + // do the highlight paint + const left = rect.left - 0.5; + const top = rect.top - 0.5; + const width = rect.width + 1; + const height = rect.height + 1; + context.strokeRect( + left < 0 ? 0 : left, + top < 0 ? 0 : top, + width > window.innerWidth ? window.innerWidth : width, + height > window.innerHeight ? window.innerHeight : height + ); + } + } catch { + void 0; } }); @@ -146,31 +150,35 @@ export class HighLight { allPendingAppend.forEach((fiber) => { if (include(fiber.state, STATE_TYPE.__unmount__)) return; - const node = fiber.nativeNode as HTMLElement; - if (node.nodeType === Node.TEXT_NODE) { - this.range.selectNodeContents(node); - } else { - this.range.selectNode(node); - } - const rect = this.range.getBoundingClientRect(); - if ( - (rect.width || rect.height) && - rect.top >= 0 && - rect.left >= 0 && - rect.right <= (window.innerWidth || document.documentElement.clientWidth) && - rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) - ) { - // do the highlight paint - const left = rect.left - 0.5; - const top = rect.top - 0.5; - const width = rect.width + 1; - const height = rect.height + 1; - context.strokeRect( - left < 0 ? 0 : left, - top < 0 ? 0 : top, - width > window.innerWidth ? window.innerWidth : width, - height > window.innerHeight ? window.innerHeight : height - ); + try { + const node = fiber.nativeNode as HTMLElement; + if (node.nodeType === Node.TEXT_NODE) { + this.range.selectNodeContents(node); + } else { + this.range.selectNode(node); + } + const rect = this.range.getBoundingClientRect(); + if ( + (rect.width || rect.height) && + rect.top >= 0 && + rect.left >= 0 && + rect.right <= (window.innerWidth || document.documentElement.clientWidth) && + rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) + ) { + // do the highlight paint + const left = rect.left - 0.5; + const top = rect.top - 0.5; + const width = rect.width + 1; + const height = rect.height + 1; + context.strokeRect( + left < 0 ? 0 : left, + top < 0 ? 0 : top, + width > window.innerWidth ? window.innerWidth : width, + height > window.innerHeight ? window.innerHeight : height + ); + } + } catch { + void 0; } }); @@ -180,31 +188,35 @@ export class HighLight { allPendingSetRef.forEach((fiber) => { if (include(fiber.state, STATE_TYPE.__unmount__)) return; - const node = fiber.nativeNode as HTMLElement; - if (node.nodeType === Node.TEXT_NODE) { - this.range.selectNodeContents(node); - } else { - this.range.selectNode(node); - } - const rect = this.range.getBoundingClientRect(); - if ( - (rect.width || rect.height) && - rect.top >= 0 && - rect.left >= 0 && - rect.right <= (window.innerWidth || document.documentElement.clientWidth) && - rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) - ) { - // do the highlight paint - const left = rect.left - 0.5; - const top = rect.top - 0.5; - const width = rect.width + 1; - const height = rect.height + 1; - context.strokeRect( - left < 0 ? 0 : left, - top < 0 ? 0 : top, - width > window.innerWidth ? window.innerWidth : width, - height > window.innerHeight ? window.innerHeight : height - ); + try { + const node = fiber.nativeNode as HTMLElement; + if (node.nodeType === Node.TEXT_NODE) { + this.range.selectNodeContents(node); + } else { + this.range.selectNode(node); + } + const rect = this.range.getBoundingClientRect(); + if ( + (rect.width || rect.height) && + rect.top >= 0 && + rect.left >= 0 && + rect.right <= (window.innerWidth || document.documentElement.clientWidth) && + rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) + ) { + // do the highlight paint + const left = rect.left - 0.5; + const top = rect.top - 0.5; + const width = rect.width + 1; + const height = rect.height + 1; + context.strokeRect( + left < 0 ? 0 : left, + top < 0 ? 0 : top, + width > window.innerWidth ? window.innerWidth : width, + height > window.innerHeight ? window.innerHeight : height + ); + } + } catch { + void 0; } }); @@ -216,31 +228,35 @@ export class HighLight { allPendingWarn.forEach((fiber) => { if (include(fiber.state, STATE_TYPE.__unmount__)) return; - const node = fiber.nativeNode as HTMLElement; - if (node.nodeType === Node.TEXT_NODE) { - this.range.selectNodeContents(node); - } else { - this.range.selectNode(node); - } - const rect = this.range.getBoundingClientRect(); - if ( - (rect.width || rect.height) && - rect.top >= 0 && - rect.left >= 0 && - rect.right <= (window.innerWidth || document.documentElement.clientWidth) && - rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) - ) { - // do the highlight paint - const left = rect.left - 0.5; - const top = rect.top - 0.5; - const width = rect.width + 1; - const height = rect.height + 1; - context.strokeRect( - left < 0 ? 0 : left, - top < 0 ? 0 : top, - width > window.innerWidth ? window.innerWidth : width, - height > window.innerHeight ? window.innerHeight : height - ); + try { + const node = fiber.nativeNode as HTMLElement; + if (node.nodeType === Node.TEXT_NODE) { + this.range.selectNodeContents(node); + } else { + this.range.selectNode(node); + } + const rect = this.range.getBoundingClientRect(); + if ( + (rect.width || rect.height) && + rect.top >= 0 && + rect.left >= 0 && + rect.right <= (window.innerWidth || document.documentElement.clientWidth) && + rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) + ) { + // do the highlight paint + const left = rect.left - 0.5; + const top = rect.top - 0.5; + const width = rect.width + 1; + const height = rect.height + 1; + context.strokeRect( + left < 0 ? 0 : left, + top < 0 ? 0 : top, + width > window.innerWidth ? window.innerWidth : width, + height > window.innerHeight ? window.innerHeight : height + ); + } + } catch { + void 0; } }); diff --git a/packages/myreact-dom/src/server/renderPlatform/feature.ts b/packages/myreact-dom/src/server/renderPlatform/feature.ts index 7f052631..fc398fdc 100644 --- a/packages/myreact-dom/src/server/renderPlatform/feature.ts +++ b/packages/myreact-dom/src/server/renderPlatform/feature.ts @@ -39,6 +39,8 @@ const dispatchError = ({ fiber, error }: { fiber: MyReactFiberNode; error: Error } else { throw error; } + + return void 0; }; /** diff --git a/packages/myreact-reactivity/src/reactive/feature.ts b/packages/myreact-reactivity/src/reactive/feature.ts index 5b301628..15aac42f 100644 --- a/packages/myreact-reactivity/src/reactive/feature.ts +++ b/packages/myreact-reactivity/src/reactive/feature.ts @@ -74,7 +74,7 @@ export function createReactive

, S extends Reco componentWillUnmount(): void { this.props.$$__instance__$$.onUnmounted.forEach((f) => f()); - this.effect.stop(); + this.reactiveEffect.stop(); } shouldComponentUpdate(): boolean { @@ -84,7 +84,7 @@ export function createReactive

, S extends Reco return true; } - effect = new ReactiveEffect(() => { + reactiveEffect = new ReactiveEffect(() => { const { children, $$__trigger__$$, $$__reactiveState__$$, $$__instance__$$, ...last } = this.props; const targetRender = (render || children) as (props: UnwrapRef & P) => LikeReactNode; const element = targetRender?.({ ...last, ...$$__reactiveState__$$ } as UnwrapRef & P) || null; @@ -92,7 +92,7 @@ export function createReactive

, S extends Reco }, this.props.$$__trigger__$$); render() { - return createElement(ForBeforeMount, { ["$$__instance__$$"]: this.props.$$__instance__$$, children: this.effect.run() }); + return createElement(ForBeforeMount, { ["$$__instance__$$"]: this.props.$$__instance__$$, children: this.reactiveEffect.run() }); } } @@ -104,10 +104,10 @@ export function createReactive

, S extends Reco } & P > { componentWillUnmount(): void { - this.effect.stop(); + this.reactiveEffect.stop(); } - effect = new ReactiveEffect(() => { + reactiveEffect = new ReactiveEffect(() => { const { children, $$__trigger__$$, $$__reactiveState__$$, $$__instance__$$, ...last } = this.props; const targetRender = (render || children) as (props: UnwrapRef & P) => LikeReactNode; const element = targetRender?.({ ...last, ...$$__reactiveState__$$ } as UnwrapRef & P) || null; @@ -115,7 +115,7 @@ export function createReactive

, S extends Reco }, this.props.$$__trigger__$$); render() { - return this.effect.run(); + return this.reactiveEffect.run(); } } diff --git a/packages/myreact-reconciler/src/dispatchContext/feature.ts b/packages/myreact-reconciler/src/dispatchContext/feature.ts index 63797881..29bb269a 100644 --- a/packages/myreact-reconciler/src/dispatchContext/feature.ts +++ b/packages/myreact-reconciler/src/dispatchContext/feature.ts @@ -1,15 +1,13 @@ -import { __my_react_internal__, __my_react_shared__ } from "@my-react/react"; -import { PATCH_TYPE, STATE_TYPE, exclude, include, remove } from "@my-react/react-shared"; +import { __my_react_shared__ } from "@my-react/react"; +import { ListTree, STATE_TYPE, UpdateQueueType, exclude, include } from "@my-react/react-shared"; import { NODE_TYPE } from "../share"; +import type { UpdateQueueDev } from "../processState"; import type { CustomRenderDispatch } from "../renderDispatch"; -import type { CustomRenderPlatform } from "../renderPlatform"; import type { MyReactFiberNode, MyReactFiberNodeDev } from "../runtimeFiber"; import type { createContext } from "@my-react/react"; -const { currentRenderPlatform } = __my_react_internal__; - const { enableDebugFiled } = __my_react_shared__; const emptyObj = {}; @@ -44,9 +42,9 @@ export const defaultGenerateContextMap = (fiber: MyReactFiberNode, map: WeakMap< export const defaultGetContextValue = (fiber: MyReactFiberNode | null, ContextObject?: ReturnType | null) => { if (fiber) { - return (fiber.pendingProps["value"] as Record); + return fiber.pendingProps["value"] as Record; } else { - return (ContextObject?.Provider["value"] as Record); + return ContextObject?.Provider["value"] as Record; } }; @@ -88,33 +86,114 @@ export const defaultGetContextFiber_New = ( } }; -export const context = (fiber: MyReactFiberNode, renderDispatch: CustomRenderDispatch) => { - if (include(fiber.patch, PATCH_TYPE.__context__)) { - const set = new Set(fiber.dependence); - - const renderPlatform = currentRenderPlatform.current as CustomRenderPlatform; +export const prepareUpdateAllDependence = (fiber: MyReactFiberNode, beforeValue: Record, afterValue: Record) => { + const consumerList = new Set(fiber?.dependence || []); + consumerList.forEach((i) => { + if (i._ownerFiber && exclude(i._ownerFiber.state, STATE_TYPE.__unmount__)) { + const typedFiber = i._ownerFiber as MyReactFiberNodeDev; + if (__DEV__ && enableDebugFiled.current) { + typedFiber._debugUpdateQueue = typedFiber._debugUpdateQueue || new ListTree(); + const now = Date.now(); + const updater: UpdateQueueDev = { + type: UpdateQueueType.context, + trigger: fiber, + payLoad: afterValue, + isSync: true, + isForce: true, + _debugBaseValue: beforeValue, + _debugBeforeValue: beforeValue, + _debugAfterValue: afterValue, + _debugCreateTime: now, + _debugRunTime: now, + _debugType: UpdateQueueType[UpdateQueueType.context], + _debugUpdateState: { + needUpdate: true, + isSync: true, + isForce: true, + callbacks: [], + }, + }; + typedFiber._debugUpdateQueue.push(updater); + } + typedFiber.state = STATE_TYPE.__triggerSyncForce__; + } + }); +}; - renderPlatform.microTask(() => { - set.forEach((i) => { - if (i._ownerFiber && exclude(i._ownerFiber.state, STATE_TYPE.__unmount__)) { - i._ownerFiber.state = STATE_TYPE.__triggerSync__; - } - }); - // TODO - renderDispatch.pendingUpdateFiberArray.clear(); - // sync skip from root - renderDispatch.rootFiber._update(STATE_TYPE.__skippedSync__); - }); - - fiber.patch = remove(fiber.patch, PATCH_TYPE.__context__); +export const prepareUpdateAllDependenceFromRoot = ( + renderDispatch: CustomRenderDispatch, + fiber: MyReactFiberNode, + beforeValue: Record, + afterValue: Record +) => { + const consumerList = new Set(fiber?.dependence || []); + const now = Date.now(); + const updater: UpdateQueueDev = { + type: UpdateQueueType.context, + trigger: fiber, + payLoad: afterValue, + isSync: true, + isForce: true, + _debugBaseValue: beforeValue, + _debugBeforeValue: beforeValue, + _debugAfterValue: afterValue, + _debugCreateTime: now, + _debugRunTime: now, + _debugType: UpdateQueueType[UpdateQueueType.context], + _debugUpdateState: { + needUpdate: true, + isSync: true, + isForce: true, + callbacks: [], + }, + }; + consumerList.forEach((i) => { + if (i._ownerFiber && exclude(i._ownerFiber.state, STATE_TYPE.__unmount__)) { + const typedFiber = i._ownerFiber as MyReactFiberNodeDev; + typedFiber.state = STATE_TYPE.__triggerSyncForce__; + } + }); + const root = renderDispatch.rootFiber as MyReactFiberNodeDev; + if (__DEV__ && enableDebugFiled.current) { + root._debugUpdateQueue = root._debugUpdateQueue || new ListTree(); + root._debugUpdateQueue.push(updater); } + renderDispatch.pendingUpdateFiberArray.clear(); + root._update(STATE_TYPE.__skippedSync__); }; -// used for root loop -export const prepareUpdateAllDependence = (fiber: MyReactFiberNode) => { - fiber?.dependence?.forEach((i) => { +export const prepareUpdateAllDependenceFromProvider = (fiber: MyReactFiberNode, beforeValue: Record, afterValue: Record) => { + const consumerList = new Set(fiber?.dependence || []); + const now = Date.now(); + const updater: UpdateQueueDev = { + type: UpdateQueueType.context, + trigger: fiber, + payLoad: afterValue, + isSync: true, + isForce: true, + _debugBaseValue: beforeValue, + _debugBeforeValue: beforeValue, + _debugAfterValue: afterValue, + _debugCreateTime: now, + _debugRunTime: now, + _debugType: UpdateQueueType[UpdateQueueType.context], + _debugUpdateState: { + needUpdate: true, + isSync: true, + isForce: true, + callbacks: [], + }, + }; + consumerList.forEach((i) => { if (i._ownerFiber && exclude(i._ownerFiber.state, STATE_TYPE.__unmount__)) { - i._ownerFiber.state = STATE_TYPE.__triggerSync__; + const typedFiber = i._ownerFiber as MyReactFiberNodeDev; + typedFiber.state = STATE_TYPE.__triggerSyncForce__; } }); + const typedFiber = fiber as MyReactFiberNodeDev; + if (__DEV__ && enableDebugFiled.current) { + typedFiber._debugUpdateQueue = typedFiber._debugUpdateQueue || new ListTree(); + typedFiber._debugUpdateQueue.push(updater); + } + typedFiber._update(STATE_TYPE.__skippedSync__); }; diff --git a/packages/myreact-reconciler/src/dispatchQueue/feature.ts b/packages/myreact-reconciler/src/dispatchQueue/feature.ts index 61cfd63b..e63a07d5 100644 --- a/packages/myreact-reconciler/src/dispatchQueue/feature.ts +++ b/packages/myreact-reconciler/src/dispatchQueue/feature.ts @@ -17,8 +17,7 @@ export const processClassComponentUpdateQueue = ( ): { needUpdate: boolean; isForce: boolean; isSync: boolean; callback?: () => void } => { if (include(fiber.state, STATE_TYPE.__unmount__)) return; - if (exclude(fiber.type, NODE_TYPE.__class__)) - throw new Error("[@my-react/react] current fiber is not a class component, look like a bug for @my-react"); + if (exclude(fiber.type, NODE_TYPE.__class__)) throw new Error("[@my-react/react] current fiber is not a class component, look like a bug for @my-react"); const renderPlatform = currentRenderPlatform.current; @@ -298,6 +297,73 @@ export const processFunctionComponentUpdateQueue = (fiber: MyReactFiberNode, ena } }; +export const processLazyComponentUpdate = (fiber: MyReactFiberNode) => { + if (include(fiber.state, STATE_TYPE.__unmount__)) return; + + if (exclude(fiber.type, NODE_TYPE.__lazy__)) throw new Error("[@my-react/react] current fiber is not a lazy component, look like a bug for @my-react"); + + const allQueue = fiber.updateQueue; + + const typedFiber = fiber as MyReactFiberNodeDev; + + if (__DEV__ && enableDebugFiled.current && allQueue) typedFiber._debugUpdateQueue = typedFiber._debugUpdateQueue || new ListTree(); + + let node = allQueue?.head; + + let needUpdate = false; + + let isSync = false; + + let isForce = false; + + const callbacks: Array<() => void> = []; + + while (node) { + const updater = node.value; + + const nextNode = node.next; + + if (updater.type === UpdateQueueType.lazy) { + if (__DEV__ && updater.trigger !== fiber) throw new Error("[@my-react/react] current update not valid, look like a bug for @my-react"); + + allQueue.delete(node); + + const { payLoad } = updater; + + isSync = isSync || updater.isSync; + + isForce = isForce || updater.isForce; + + needUpdate = true; + + updater.callback && callbacks.push(updater.callback); + + if (__DEV__ && enableDebugFiled.current) { + const typedNode = node.value as UpdateQueueDev; + + typedNode._debugRunTime = Date.now(); + + typedNode._debugBeforeValue = null; + + typedNode._debugAfterValue = payLoad; + + typedNode._debugUpdateState = { needUpdate, isSync, isForce, callbacks: callbacks.slice(0) }; + + typedFiber._debugUpdateQueue.push(typedNode); + } + } + + node = nextNode; + } + + return { + needUpdate, + isSync, + isForce, + callback: callbacks.length ? () => callbacks.forEach((cb) => cb?.()) : void 0, + }; +}; + /** * @deprecated */ diff --git a/packages/myreact-reconciler/src/dispatchUpdate/feature.ts b/packages/myreact-reconciler/src/dispatchUpdate/feature.ts index 1f9c48ce..cce023a3 100644 --- a/packages/myreact-reconciler/src/dispatchUpdate/feature.ts +++ b/packages/myreact-reconciler/src/dispatchUpdate/feature.ts @@ -1,7 +1,6 @@ import { __my_react_internal__ } from "@my-react/react"; import { STATE_TYPE, exclude } from "@my-react/react-shared"; -import { context } from "../dispatchContext"; import { effect, insertionEffect, layoutEffect } from "../dispatchEffect"; import { unmount } from "../dispatchUnmount"; import { afterSyncUpdate, beforeSyncUpdate, safeCallWithFiber } from "../share"; @@ -63,7 +62,6 @@ export const defaultDispatchUpdate = (_list: ListTree, _dispat _list.listToFoot((_fiber) => { if (exclude(_fiber.state, STATE_TYPE.__unmount__) && !_dispatch.isAppUnmounted) { - context(_fiber, _dispatch); layoutEffect(_fiber, _dispatch); } }); diff --git a/packages/myreact-reconciler/src/processState/feature.ts b/packages/myreact-reconciler/src/processState/feature.ts index efa8d2d6..16663a7c 100644 --- a/packages/myreact-reconciler/src/processState/feature.ts +++ b/packages/myreact-reconciler/src/processState/feature.ts @@ -93,7 +93,7 @@ export const processState = (_params: UpdateQueue) => { ownerFiber.updateQueue.push(_params); ownerFiber._prepare(_params.isInitial && renderDispatch?.isAppMounted); - } else { + } else if (_params.type === UpdateQueueType.hook) { const ownerFiber = _params.trigger._ownerFiber as MyReactFiberNode; if (!ownerFiber || include(ownerFiber?.state, STATE_TYPE.__unmount__)) return; @@ -143,6 +143,20 @@ export const processState = (_params: UpdateQueue) => { ownerFiber.updateQueue.push(_params); + ownerFiber._prepare(_params.isInitial && renderDispatch?.isAppMounted); + } else { + const ownerFiber = _params.trigger as MyReactFiberNode; + + if (!ownerFiber || include(ownerFiber.state, STATE_TYPE.__unmount__)) return; + + const renderDispatch = getCurrentDispatchFromFiber(ownerFiber); + + if (!renderDispatch.enableUpdate) return; + + ownerFiber.updateQueue = ownerFiber.updateQueue || new ListTree(); + + ownerFiber.updateQueue.push(_params); + ownerFiber._prepare(_params.isInitial && renderDispatch?.isAppMounted); } }; diff --git a/packages/myreact-reconciler/src/renderDispatch/instance.ts b/packages/myreact-reconciler/src/renderDispatch/instance.ts index 720f7dad..2e8c245e 100644 --- a/packages/myreact-reconciler/src/renderDispatch/instance.ts +++ b/packages/myreact-reconciler/src/renderDispatch/instance.ts @@ -100,9 +100,6 @@ export class CustomRenderDispatch implements RenderDispatch { _fiber.patch = merge(_fiber.patch, PATCH_TYPE.__append__); } } - pendingContext(_fiber: MyReactFiberNode): void { - _fiber.patch = merge(_fiber.patch, PATCH_TYPE.__context__); - } pendingPosition(_fiber: MyReactFiberNode): void { _fiber.patch = merge(_fiber.patch, PATCH_TYPE.__position__); } diff --git a/packages/myreact-reconciler/src/renderDispatch/interface.ts b/packages/myreact-reconciler/src/renderDispatch/interface.ts index 6a354e97..5ab1a5ab 100644 --- a/packages/myreact-reconciler/src/renderDispatch/interface.ts +++ b/packages/myreact-reconciler/src/renderDispatch/interface.ts @@ -60,8 +60,6 @@ type DefaultRenderDispatch = { pendingAppend(_fiber: MyReactFiberNode): void; - pendingContext(_fiber: MyReactFiberNode): void; - pendingPosition(_fiber: MyReactFiberNode): void; pendingRef(_fiber: MyReactFiberNode): void; diff --git a/packages/myreact-reconciler/src/renderPlatform/instance.ts b/packages/myreact-reconciler/src/renderPlatform/instance.ts index a133584b..9c82c903 100644 --- a/packages/myreact-reconciler/src/renderPlatform/instance.ts +++ b/packages/myreact-reconciler/src/renderPlatform/instance.ts @@ -5,7 +5,7 @@ import { getFiberTree, getHookTree } from "../share"; import type { CustomRenderDispatch } from "../renderDispatch"; import type { MyReactFiberNode } from "../runtimeFiber"; import type { MyReactHookNode } from "../runtimeHook"; -import type { RenderFiber, RenderHookParams, RenderPlatform, UpdateQueue } from "@my-react/react"; +import type { MyReactElementNode, RenderFiber, RenderHookParams, RenderPlatform, UpdateQueue } from "@my-react/react"; import type { ListTreeNode, HOOK_TYPE } from "@my-react/react-shared"; export class CustomRenderPlatform implements RenderPlatform { @@ -30,12 +30,12 @@ export class CustomRenderPlatform implements RenderPlatform { dispatchState(_params: UpdateQueue): void { void 0; } - dispatchError(_params: { fiber?: RenderFiber; error?: Error }): void { - void 0; + dispatchError(_params: { fiber?: RenderFiber; error?: Error }): MyReactElementNode { + return void 0; } - dispatchPromise(_params: { fiber?: RenderFiber; promise?: Promise }): void { - void 0; + dispatchPromise(_params: { fiber?: RenderFiber; promise?: Promise }): MyReactElementNode { + return void 0; } dispatchSet = new UniqueArray(); diff --git a/packages/myreact-reconciler/src/renderUpdate/trigger.ts b/packages/myreact-reconciler/src/renderUpdate/trigger.ts index 4f81f57c..ad6f3e2e 100644 --- a/packages/myreact-reconciler/src/renderUpdate/trigger.ts +++ b/packages/myreact-reconciler/src/renderUpdate/trigger.ts @@ -1,5 +1,5 @@ import { __my_react_internal__, __my_react_shared__ } from "@my-react/react"; -import { STATE_TYPE, exclude, include, merge } from "@my-react/react-shared"; +import { MODE_TYPE, STATE_TYPE, exclude, include, merge } from "@my-react/react-shared"; import { isErrorBoundariesComponent } from "../dispatchErrorBoundaries"; import { unmountFiber } from "../dispatchUnmount"; @@ -189,7 +189,7 @@ export const triggerUpdate = (fiber: MyReactFiberNode, state?: STATE_TYPE, cb?: fiber.state = merge(fiber.state, state); } - fiber.mode = 1; + fiber.mode = MODE_TYPE.__stable__; renderDispatch.pendingUpdateFiberArray.uniPush(fiber); diff --git a/packages/myreact-reconciler/src/runtimeComponent/feature.ts b/packages/myreact-reconciler/src/runtimeComponent/feature.ts index 586bf236..be8bd880 100644 --- a/packages/myreact-reconciler/src/runtimeComponent/feature.ts +++ b/packages/myreact-reconciler/src/runtimeComponent/feature.ts @@ -84,11 +84,11 @@ const processComponentDidMountOnMount = (fiber: MyReactFiberNode) => { const renderDispatch = currentRenderDispatch.current; - if (typedInstance.componentDidMount && exclude(typedInstance.mode, Effect_TYPE.__effect__)) { - typedInstance.mode = Effect_TYPE.__effect__; + if (typedInstance.componentDidMount && exclude(typedInstance.effect, Effect_TYPE.__effect__)) { + typedInstance.effect = Effect_TYPE.__effect__; renderDispatch.pendingLayoutEffect(fiber, () => { - typedInstance.mode = Effect_TYPE.__initial__; + typedInstance.effect = Effect_TYPE.__initial__; typedInstance.componentDidMount?.(); }); @@ -176,11 +176,11 @@ const processComponentDidUpdateOnUpdate = ( const renderDispatch = currentRenderDispatch.current; - if (typedInstance.componentDidUpdate && exclude(typedInstance.mode, Effect_TYPE.__effect__)) { - typedInstance.mode = Effect_TYPE.__effect__; + if (typedInstance.componentDidUpdate && exclude(typedInstance.effect, Effect_TYPE.__effect__)) { + typedInstance.effect = Effect_TYPE.__effect__; renderDispatch.pendingLayoutEffect(fiber, () => { - typedInstance.mode = Effect_TYPE.__initial__; + typedInstance.effect = Effect_TYPE.__initial__; typedInstance.componentDidUpdate?.(baseProps, baseState, snapshot); }); diff --git a/packages/myreact-reconciler/src/runtimeFiber/instance.ts b/packages/myreact-reconciler/src/runtimeFiber/instance.ts index 33728a40..50acf294 100644 --- a/packages/myreact-reconciler/src/runtimeFiber/instance.ts +++ b/packages/myreact-reconciler/src/runtimeFiber/instance.ts @@ -1,13 +1,13 @@ import { __my_react_internal__, __my_react_shared__ } from "@my-react/react"; -import { PATCH_TYPE, STATE_TYPE, include } from "@my-react/react-shared"; +import { PATCH_TYPE, STATE_TYPE, include , MODE_TYPE } from "@my-react/react-shared"; -import { processClassComponentUpdateQueue, processFunctionComponentUpdateQueue } from "../dispatchQueue"; +import { processClassComponentUpdateQueue, processFunctionComponentUpdateQueue, processLazyComponentUpdate } from "../dispatchQueue"; import { triggerRevert, triggerUpdate } from "../renderUpdate"; import { getFiberTreeWithFiber, getTypeFromElementNode, NODE_TYPE } from "../share"; import type { MyReactFiberNodeDev } from "./interface"; import type { MyReactElement, MyReactElementNode, MyReactElementType, MyReactInternalInstance, RenderFiber, RenderHook, UpdateQueue } from "@my-react/react"; -import type { ListTree } from "@my-react/react-shared"; +import type { ListTree} from "@my-react/react-shared"; type NativeNode = Record; @@ -28,7 +28,7 @@ export class MyReactFiberNode implements RenderFiber { type: NODE_TYPE = NODE_TYPE.__initial__; - mode: 0 | 1 = 0; + mode: MODE_TYPE = MODE_TYPE.__initial__; nativeNode: Record; @@ -112,7 +112,13 @@ export class MyReactFiberNode implements RenderFiber { const updateState = include(this.type, NODE_TYPE.__class__) ? processClassComponentUpdateQueue(this, flag) - : processFunctionComponentUpdateQueue(this, flag); + : include(this.type, NODE_TYPE.__function__) + ? processFunctionComponentUpdateQueue(this, flag) + : include(this.type, NODE_TYPE.__lazy__) + ? processLazyComponentUpdate(this) + : (() => { + throw new Error("unknown runtime error, this is a bug for @my-react"); + })(); if (updateState?.needUpdate) { if (updateState.isSync) { diff --git a/packages/myreact-reconciler/src/runtimeFiber/update.ts b/packages/myreact-reconciler/src/runtimeFiber/update.ts index ae2e5214..83055574 100644 --- a/packages/myreact-reconciler/src/runtimeFiber/update.ts +++ b/packages/myreact-reconciler/src/runtimeFiber/update.ts @@ -1,7 +1,7 @@ import { __my_react_shared__ } from "@my-react/react"; import { exclude, include, isNormalEquals, merge, PATCH_TYPE, remove, STATE_TYPE } from "@my-react/react-shared"; -import { prepareUpdateAllDependence } from "../dispatchContext"; +import { prepareUpdateAllDependence, prepareUpdateAllDependenceFromProvider } from "../dispatchContext"; import { currentRenderDispatch, NODE_TYPE } from "../share"; import type { MyReactFiberNode } from "./instance"; @@ -74,11 +74,10 @@ export const updateFiberNode = ( if (fiber.state !== STATE_TYPE.__stable__) { if (include(fiber.type, NODE_TYPE.__provider__)) { if (!isNormalEquals(fiber.pendingProps.value as Record, fiber.memoizedProps.value as Record)) { - // if current is root loop mode, should not delay context update if (enableLoopFromRoot.current) { - prepareUpdateAllDependence(fiber); + prepareUpdateAllDependence(fiber, fiber.memoizedProps.value, fiber.pendingProps.value); } else { - renderDispatch.pendingContext(fiber); + renderDispatch.pendingLayoutEffect(fiber, () => prepareUpdateAllDependenceFromProvider(fiber, fiber.memoizedProps.value, fiber.pendingProps.value)); } } } diff --git a/packages/myreact-reconciler/src/runtimeHook/create.ts b/packages/myreact-reconciler/src/runtimeHook/create.ts index 283e5fb4..0bbffcfc 100644 --- a/packages/myreact-reconciler/src/runtimeHook/create.ts +++ b/packages/myreact-reconciler/src/runtimeHook/create.ts @@ -1,7 +1,6 @@ import { __my_react_internal__, __my_react_shared__, startTransition } from "@my-react/react"; -import { HOOK_TYPE, STATE_TYPE } from "@my-react/react-shared"; +import { HOOK_TYPE } from "@my-react/react-shared"; -import { triggerUpdate } from "../renderUpdate"; import { currentRenderDispatch, safeCallWithFiber } from "../share"; import { checkHookValid } from "./check"; @@ -49,7 +48,7 @@ export const createHookNode = ({ type, value, reducer, deps }: RenderHookParams, hookNode.type === HOOK_TYPE.useInsertionEffect || hookNode.type === HOOK_TYPE.useImperativeHandle ) { - hookNode.effect = true; + hookNode.hasEffect = true; } if (hookNode.type === HOOK_TYPE.useRef || hookNode.type === HOOK_TYPE.useCallback || hookNode.type === HOOK_TYPE.useDeferredValue) { @@ -88,11 +87,11 @@ export const createHookNode = ({ type, value, reducer, deps }: RenderHookParams, renderDispatch.isAppMounted ? storeApi.getSnapshot.call(null) : storeApi.getServerSnapshot - ? storeApi.getServerSnapshot?.call(null) - : storeApi.getSnapshot.call(null), + ? storeApi.getServerSnapshot?.call(null) + : storeApi.getSnapshot.call(null), }); - hookNode.effect = true; + hookNode.hasEffect = true; } if (hookNode.type === HOOK_TYPE.useSignal) { @@ -106,14 +105,14 @@ export const createHookNode = ({ type, value, reducer, deps }: RenderHookParams, const loadingCallback = (cb: () => void) => { startTransition(() => { hookNode.result[0] = true; - triggerUpdate(fiber, STATE_TYPE.__triggerConcurrent__, cb); + hookNode._internalDispatch({ isForce: true, callback: cb }); }); }; const loadedCallback = () => { startTransition(() => { hookNode.result[0] = false; - triggerUpdate(fiber, STATE_TYPE.__triggerConcurrent__); + hookNode._internalDispatch({ isForce: true }); }); }; diff --git a/packages/myreact-reconciler/src/runtimeHook/effect.ts b/packages/myreact-reconciler/src/runtimeHook/effect.ts index 1442f84a..6a1312f8 100644 --- a/packages/myreact-reconciler/src/runtimeHook/effect.ts +++ b/packages/myreact-reconciler/src/runtimeHook/effect.ts @@ -8,8 +8,8 @@ import type { MyReactFiberNode } from "../runtimeFiber"; export const effectHookNode = (fiber: MyReactFiberNode, hookNode: MyReactHookNode) => { const renderDispatch = currentRenderDispatch.current; - if (hookNode.effect && hookNode.mode === Effect_TYPE.__initial__) { - hookNode.mode = Effect_TYPE.__effect__; + if (hookNode.hasEffect && (hookNode.effect as Effect_TYPE) === Effect_TYPE.__initial__) { + hookNode.effect = Effect_TYPE.__effect__; if (hookNode.type === HOOK_TYPE.useEffect) { renderDispatch.pendingEffect(fiber, () => { @@ -17,9 +17,9 @@ export const effectHookNode = (fiber: MyReactFiberNode, hookNode: MyReactHookNod if (hookNode._ownerFiber && exclude(hookNode._ownerFiber.state, STATE_TYPE.__unmount__)) hookNode.cancel = hookNode.value(); - hookNode.effect = false; + hookNode.hasEffect = false; - hookNode.mode = Effect_TYPE.__initial__; + hookNode.effect = Effect_TYPE.__initial__; }); } @@ -29,9 +29,9 @@ export const effectHookNode = (fiber: MyReactFiberNode, hookNode: MyReactHookNod hookNode.cancel = hookNode.value(); - hookNode.effect = false; + hookNode.hasEffect = false; - hookNode.mode = Effect_TYPE.__initial__; + hookNode.effect = Effect_TYPE.__initial__; }); } @@ -41,9 +41,9 @@ export const effectHookNode = (fiber: MyReactFiberNode, hookNode: MyReactHookNod hookNode.cancel = hookNode.value(); - hookNode.effect = false; + hookNode.hasEffect = false; - hookNode.mode = Effect_TYPE.__initial__; + hookNode.effect = Effect_TYPE.__initial__; }); } @@ -54,9 +54,9 @@ export const effectHookNode = (fiber: MyReactFiberNode, hookNode: MyReactHookNod // ref function if (hookNode.value && typeof hookNode.value === "function") hookNode.value(hookNode.reducer.call(null)); - hookNode.effect = false; + hookNode.hasEffect = false; - hookNode.mode = Effect_TYPE.__initial__; + hookNode.effect = Effect_TYPE.__initial__; }); } @@ -68,9 +68,9 @@ export const effectHookNode = (fiber: MyReactFiberNode, hookNode: MyReactHookNod hookNode.cancel = storeApi.subscribe(() => hookNode._internalDispatch({ isForce: true })); - hookNode.effect = false; + hookNode.hasEffect = false; - hookNode.mode = Effect_TYPE.__initial__; + hookNode.effect = Effect_TYPE.__initial__; }); } } diff --git a/packages/myreact-reconciler/src/runtimeHook/instance.ts b/packages/myreact-reconciler/src/runtimeHook/instance.ts index 9ff90ee0..3b867bc7 100644 --- a/packages/myreact-reconciler/src/runtimeHook/instance.ts +++ b/packages/myreact-reconciler/src/runtimeHook/instance.ts @@ -1,5 +1,5 @@ import { __my_react_internal__, __my_react_shared__ } from "@my-react/react"; -import { UpdateQueueType } from "@my-react/react-shared"; +import { MODE_TYPE, UpdateQueueType } from "@my-react/react-shared"; import type { UpdateQueueDev } from "../processState"; import type { RenderHook, Action, HookUpdateQueue } from "@my-react/react"; @@ -16,7 +16,7 @@ export class MyReactHookNode extends MyReactInternalInstance implements RenderHo reducer: RenderHook["reducer"]; - effect = false; + hasEffect = false; cancel?: () => void; @@ -38,7 +38,7 @@ export class MyReactHookNode extends MyReactInternalInstance implements RenderHo _unmount() { super._unmount(); - this.effect = false; + this.hasEffect = false; this.cancel && this.cancel(); } @@ -49,7 +49,7 @@ export class MyReactHookNode extends MyReactInternalInstance implements RenderHo payLoad: action, isForce: false, isSync: enableSyncFlush.current, - isInitial: this._ownerFiber?.mode === 0, + isInitial: this._ownerFiber?.mode === MODE_TYPE.__initial__, }; const renderPlatform = currentRenderPlatform.current; @@ -65,7 +65,7 @@ export class MyReactHookNode extends MyReactInternalInstance implements RenderHo isSync: enableSyncFlush.current, isForce: params.isForce, callback: params.callback, - isInitial: this._ownerFiber?.mode === 0, + isInitial: this._ownerFiber?.mode === MODE_TYPE.__initial__, }; const renderPlatform = currentRenderPlatform.current; diff --git a/packages/myreact-reconciler/src/runtimeHook/update.ts b/packages/myreact-reconciler/src/runtimeHook/update.ts index d2111ecb..af750245 100644 --- a/packages/myreact-reconciler/src/runtimeHook/update.ts +++ b/packages/myreact-reconciler/src/runtimeHook/update.ts @@ -65,7 +65,7 @@ export const updateHookNode = ({ type, value, reducer, deps }: RenderHookParams, currentHook.deps = deps; - currentHook.effect = true; + currentHook.hasEffect = true; } return currentHook; } @@ -78,7 +78,7 @@ export const updateHookNode = ({ type, value, reducer, deps }: RenderHookParams, if (isHMR || !Object.is(storeApi.subscribe, newStoreApi.subscribe)) { storeApi.subscribe = newStoreApi.subscribe; - currentHook.effect = true; + currentHook.hasEffect = true; } storeApi.getSnapshot = newStoreApi.getSnapshot; @@ -147,7 +147,7 @@ export const updateHookNode = ({ type, value, reducer, deps }: RenderHookParams, if (!Object.is(currentHook.value, currentHook.result)) { currentHook.cancel = renderPlatform.yieldTask(() => { currentHook.result = currentHook.value; - currentHook._ownerFiber?._update(); + currentHook._internalDispatch({ isForce: true }); currentHook.cancel = null; }); } diff --git a/packages/myreact-shared/src/listTree.ts b/packages/myreact-shared/src/listTree.ts index 2fa6cb31..5dad1d18 100644 --- a/packages/myreact-shared/src/listTree.ts +++ b/packages/myreact-shared/src/listTree.ts @@ -325,7 +325,7 @@ export class ListTree { } if (__DEV__) { - Object.defineProperty(ListTree.prototype, "__array__", { + Object.defineProperty(ListTree.prototype, "_debugToArray", { get(this: ListTree) { return this.toArray(); }, diff --git a/packages/myreact-shared/src/symbol/fiberMode.ts b/packages/myreact-shared/src/symbol/fiberMode.ts new file mode 100644 index 00000000..98d50a99 --- /dev/null +++ b/packages/myreact-shared/src/symbol/fiberMode.ts @@ -0,0 +1,4 @@ +export enum MODE_TYPE { + __initial__ = 0, + __stable__ = 1, +} \ No newline at end of file diff --git a/packages/myreact-shared/src/symbol/fiberPatch.ts b/packages/myreact-shared/src/symbol/fiberPatch.ts index 2027f1bc..8137b039 100644 --- a/packages/myreact-shared/src/symbol/fiberPatch.ts +++ b/packages/myreact-shared/src/symbol/fiberPatch.ts @@ -4,10 +4,9 @@ export enum PATCH_TYPE { __update__ = 1 << 1, __append__ = 1 << 2, __position__ = 1 << 3, - __context__ = 1 << 4, - __effect__ = 1 << 5, - __layoutEffect__ = 1 << 6, - __insertionEffect__ = 1 << 7, - __unmount__ = 1 << 8, - __ref__ = 1 << 9, + __effect__ = 1 << 4, + __layoutEffect__ = 1 << 5, + __insertionEffect__ = 1 << 6, + __unmount__ = 1 << 7, + __ref__ = 1 << 8, } diff --git a/packages/myreact-shared/src/symbol/index.ts b/packages/myreact-shared/src/symbol/index.ts index 2670cc20..b6ed1033 100644 --- a/packages/myreact-shared/src/symbol/index.ts +++ b/packages/myreact-shared/src/symbol/index.ts @@ -1,5 +1,6 @@ export * from "./hookType"; export * from "./queueType"; +export * from "./fiberMode"; export * from "./fiberState"; export * from "./fiberPatch"; export * from "./instanceEffect"; diff --git a/packages/myreact-shared/src/symbol/queueType.ts b/packages/myreact-shared/src/symbol/queueType.ts index 4786bd6c..a82290ae 100644 --- a/packages/myreact-shared/src/symbol/queueType.ts +++ b/packages/myreact-shared/src/symbol/queueType.ts @@ -1,4 +1,6 @@ export enum UpdateQueueType { hook = 2, component = 1, + lazy = 3, + context = 4, } diff --git a/packages/myreact/src/component/instance.ts b/packages/myreact/src/component/instance.ts index 5f4e9321..a0beb123 100644 --- a/packages/myreact/src/component/instance.ts +++ b/packages/myreact/src/component/instance.ts @@ -1,4 +1,4 @@ -import { UpdateQueueType, isNormalEquals } from "@my-react/react-shared"; +import { MODE_TYPE, UpdateQueueType, isNormalEquals } from "@my-react/react-shared"; import { MyReactInternalInstance } from "../internal"; import { currentRenderPlatform, enableSyncFlush } from "../share"; @@ -92,7 +92,7 @@ export class MyReactComponent< trigger: this, isForce: false, isSync: enableSyncFlush.current, - isInitial: this._ownerFiber?.mode === 0, + isInitial: this._ownerFiber?.mode === MODE_TYPE.__initial__, }; const renderPlatform = currentRenderPlatform.current; @@ -106,7 +106,7 @@ export class MyReactComponent< trigger: this, isForce: true, isSync: enableSyncFlush.current, - isInitial: this._ownerFiber?.mode === 0, + isInitial: this._ownerFiber?.mode === MODE_TYPE.__initial__, }; const renderPlatform = currentRenderPlatform.current; diff --git a/packages/myreact/src/element/feature.ts b/packages/myreact/src/element/feature.ts index 01f19a4c..1527350e 100644 --- a/packages/myreact/src/element/feature.ts +++ b/packages/myreact/src/element/feature.ts @@ -1,8 +1,10 @@ import { Consumer, Context, ForwardRef, isNormalEquals, Lazy, Memo, Provider, TYPEKEY } from "@my-react/react-shared"; import { MyReactInternalInstance } from "../internal"; +import { lazyLoaded } from "../share"; import type { CreateElementConfig, MixinMyReactClassComponent, MixinMyReactFunctionComponent, MyReactElement } from "./instance"; +import type { RenderFiber } from "../renderFiber"; let contextId = 0; @@ -121,6 +123,7 @@ export const lazy = ( loader, _loading: false, _loaded: false, + _update: lazyLoaded, render: null, }; return config as { @@ -128,6 +131,7 @@ export const lazy = ( loader: () => Promise<{ default: MixinMyReactFunctionComponent | MixinMyReactClassComponent } | MixinMyReactFunctionComponent | MixinMyReactClassComponent>; _loading: boolean; _loaded: boolean; + _update: (fiber: RenderFiber, loaded: null | MixinMyReactFunctionComponent | MixinMyReactClassComponent) => void; render: null | MixinMyReactFunctionComponent | MixinMyReactClassComponent; }; }; diff --git a/packages/myreact/src/internal/instance.ts b/packages/myreact/src/internal/instance.ts index f3c0e63f..1a3d1455 100644 --- a/packages/myreact/src/internal/instance.ts +++ b/packages/myreact/src/internal/instance.ts @@ -38,7 +38,7 @@ export class MyReactInternalInstance { } } - mode: Effect_TYPE = Effect_TYPE.__initial__; + effect: Effect_TYPE = Effect_TYPE.__initial__; context: null | unknown = null; @@ -59,7 +59,7 @@ export class MyReactInternalInstance { } _unmount() { - this.mode = Effect_TYPE.__unmount__; + this.effect = Effect_TYPE.__unmount__; this._contextFiber?._removeDependence(this); diff --git a/packages/myreact/src/renderFiber/interface.ts b/packages/myreact/src/renderFiber/interface.ts index 674c2ea2..3915fdd4 100644 --- a/packages/myreact/src/renderFiber/interface.ts +++ b/packages/myreact/src/renderFiber/interface.ts @@ -1,7 +1,7 @@ import type { MyReactInternalInstance } from "../internal"; import type { RenderHook } from "../renderHook"; import type { UpdateQueue } from "../renderQueue"; -import type { ListTree, PATCH_TYPE, STATE_TYPE } from "@my-react/react-shared"; +import type { ListTree, MODE_TYPE, PATCH_TYPE, STATE_TYPE } from "@my-react/react-shared"; /** * @public @@ -11,7 +11,7 @@ export interface DefaultRenderFiber { patch: PATCH_TYPE; - mode: 0 | 1; + mode: MODE_TYPE; hookList: ListTree | null; diff --git a/packages/myreact/src/renderPlatform/interface.ts b/packages/myreact/src/renderPlatform/interface.ts index 4b1f3ae6..1cc52267 100644 --- a/packages/myreact/src/renderPlatform/interface.ts +++ b/packages/myreact/src/renderPlatform/interface.ts @@ -24,6 +24,7 @@ export interface DefaultRenderPlatform { dispatchError(_params: { fiber?: RenderFiber; error?: Error }): MyReactElementNode; + // TODO maybe? dispatchPromise(_params: { fiber?: RenderFiber; promise?: Promise }): MyReactElementNode; } diff --git a/packages/myreact/src/renderQueue/interface.ts b/packages/myreact/src/renderQueue/interface.ts index b8c81889..78a6b654 100644 --- a/packages/myreact/src/renderQueue/interface.ts +++ b/packages/myreact/src/renderQueue/interface.ts @@ -1,4 +1,6 @@ import type { MyReactComponent } from "../component"; +import type { MixinMyReactClassComponent, MixinMyReactFunctionComponent } from "../element"; +import type { RenderFiber } from "../renderFiber"; import type { Action, RenderHook } from "../renderHook"; import type { UpdateQueueType } from "@my-react/react-shared"; @@ -31,4 +33,30 @@ export type HookUpdateQueue = { /** * @public */ -export type UpdateQueue> = (ComponentUpdateQueue | HookUpdateQueue) & T; +export type LazyUpdateQueue = { + type: UpdateQueueType.lazy; + trigger: RenderFiber; + isForce?: boolean; + isSync?: boolean; + isInitial?: boolean; + payLoad?: MixinMyReactFunctionComponent | MixinMyReactClassComponent; + callback?: () => void; +}; + +/** + * @public + */ +export type ContextUpdateQueue = { + type: UpdateQueueType.context; + trigger: RenderFiber; + isForce?: boolean; + isSync?: boolean; + isInitial?: boolean; + payLoad?: Record; + callback?: () => void; +}; + +/** + * @public + */ +export type UpdateQueue> = (ComponentUpdateQueue | HookUpdateQueue | LazyUpdateQueue | ContextUpdateQueue) & T; diff --git a/packages/myreact/src/share/env.ts b/packages/myreact/src/share/env.ts index ab9ddf0b..f31ea902 100644 --- a/packages/myreact/src/share/env.ts +++ b/packages/myreact/src/share/env.ts @@ -81,7 +81,7 @@ export const enablePerformanceLog = createRef(true); /** * @internal */ -export const enableDoubleRender = createRef(true); +export const enableDoubleRender = createRef(false); // support "unsafe_" lifecycle /** @@ -105,7 +105,7 @@ export const enableDebugFiled = createRef(true); /** * @internal */ -export const enableMockReact = createReadonlyRef(true); +export const enableMockReact = createReadonlyRef(false); /** * @internal diff --git a/packages/myreact/src/share/index.ts b/packages/myreact/src/share/index.ts index 4028535e..847271a3 100644 --- a/packages/myreact/src/share/index.ts +++ b/packages/myreact/src/share/index.ts @@ -1,5 +1,6 @@ export * from "./env"; export * from "./task"; +export * from "./lazy"; export * from "./platform"; export * from "./createRef"; export * from "./transition"; diff --git a/packages/myreact/src/share/lazy.ts b/packages/myreact/src/share/lazy.ts new file mode 100644 index 00000000..2f771739 --- /dev/null +++ b/packages/myreact/src/share/lazy.ts @@ -0,0 +1,22 @@ +import { MODE_TYPE, UpdateQueueType } from "@my-react/react-shared"; + +import { currentRenderPlatform } from "./env"; + +import type { MixinMyReactClassComponent, MixinMyReactFunctionComponent } from "../element"; +import type { RenderFiber } from "../renderFiber"; +import type { LazyUpdateQueue } from "../renderQueue"; + +export const lazyLoaded = (fiber: RenderFiber, loaded: null | MixinMyReactFunctionComponent | MixinMyReactClassComponent) => { + const updater: LazyUpdateQueue = { + type: UpdateQueueType.lazy, + payLoad: loaded, + trigger: fiber, + isForce: true, + isSync: true, + isInitial: fiber.mode === MODE_TYPE.__initial__, + }; + + const renderPlatform = currentRenderPlatform.current; + + renderPlatform?.dispatchState(updater); +}; diff --git a/ui/ssr-example/src/client/app.tsx b/ui/ssr-example/src/client/app.tsx index 1425183b..3b68f9dd 100644 --- a/ui/ssr-example/src/client/app.tsx +++ b/ui/ssr-example/src/client/app.tsx @@ -15,7 +15,7 @@ const Root = ({ store }: { store: ReturnType }) => // this component will only run once when the page mount, so it's ok to use server's cookie const cookieStore = cookieStorageManagerSSR(document.cookie); -const emotionCache = createEmotionCache(); + const emotionCache = createEmotionCache(); return (