Skip to content

Commit 71f2509

Browse files
Merge pull request #443 from preactjs/v11-owner
2 parents 8e7dba6 + 47c3962 commit 71f2509

File tree

2 files changed

+68
-3
lines changed

2 files changed

+68
-3
lines changed

src/adapter/11/bindings.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { RendererConfig } from "../shared/renderer";
22
import { ComponentHooks, HookState, PreactBindings } from "../shared/bindings";
33
import { HookType } from "../shared/hooks";
4+
import { VNodeV11 } from "./options";
45

56
export interface Internal {
67
type: any;
@@ -297,6 +298,10 @@ export function isPortal(internal: Internal): boolean {
297298
return "__P" in internal.props || "_parentDom" in internal.props;
298299
}
299300

301+
export function getVNodeId(vnode: VNodeV11): number {
302+
return vnode._vnodeId || vnode.__v || 0;
303+
}
304+
300305
export const bindingsV11: PreactBindings<Internal> = {
301306
isRoot,
302307
getDisplayName,

src/adapter/11/options.ts

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
getStatefulHookValue,
1010
TYPE_COMPONENT,
1111
isRoot,
12+
getVNodeId,
1213
} from "./bindings";
1314
import { RendererConfig } from "../shared/renderer";
1415
import { Renderer } from "../renderer";
@@ -31,6 +32,8 @@ import { getRenderReasonPre, RenderReasonTmpData } from "./renderReason";
3132
export interface VNodeV11<P = Record<string, unknown>> {
3233
type: ComponentType<P> | string | null;
3334
props: P;
35+
_vnodeId?: number;
36+
__v?: number;
3437
}
3538

3639
export interface OptionsV11 {
@@ -63,6 +66,7 @@ export interface OptionsV11 {
6366
_catchError?(error: any, internal: Internal): void;
6467
__e?(error: any, internal: Internal): void;
6568

69+
vnode(vnode: VNodeV11): void;
6670
_internal?(internal: Internal, vnode: VNodeV11 | string): void;
6771
__i?(internal: Internal, vnode: VNodeV11 | string): void;
6872

@@ -107,21 +111,27 @@ export function setupOptionsV11(
107111
const timings = createVNodeTimings<Internal>();
108112
let renderReasons = new Map<Internal, RenderReasonData>();
109113
let reasonTmpData = new Map<Internal, RenderReasonTmpData>();
110-
const owners = new Map();
114+
const vnodeIdToOwner = new Map<number, Internal>();
115+
const owners = new Map<Internal, Internal>();
116+
let ownerStack: Internal[] = [];
111117

112118
const o = options;
113119

114120
// Store (possible) previous hooks so that we don't overwrite them
115-
const prevVNodeHook = options._internal;
121+
const prevVNodeHook = options.vnode;
122+
const prevInternalHook = options._internal || o.__i;
116123
const prevCommitRoot = o._commit || o.__c;
117124
const prevBeforeUnmount = options.unmount;
118125
const prevBeforeDiff = o._diff || o.__b;
126+
const prevRender = o._render || o.__r;
119127
const prevAfterDiff = options.diffed;
120128
let prevHook = o._hook || o.__h;
121129
let prevUseDebugValue = options.useDebugValue;
122130
// @ts-ignore
123131
let prevHookName = options.useDebugName;
124132

133+
const skipEffects = o._skipEffects || o.__s;
134+
125135
// Make sure that we are always the first `option._hook` to be called.
126136
// This is necessary to ensure that our callstack remains consistent.
127137
// Othwerwise we'll end up with an unknown number of frames in-between
@@ -159,12 +169,41 @@ export function setupOptionsV11(
159169
};
160170
}, 100);
161171

172+
options.vnode = vnode => {
173+
if (
174+
ownerStack.length > 0 &&
175+
typeof vnode.type === "function" &&
176+
vnode.type !== config.Fragment
177+
) {
178+
vnodeIdToOwner.set(getVNodeId(vnode), ownerStack[ownerStack.length - 1]);
179+
}
180+
if (prevVNodeHook) prevVNodeHook(vnode);
181+
};
182+
183+
options._internal = options.__i = (internal, vnode) => {
184+
const owner = vnodeIdToOwner.get(getVNodeId(internal));
185+
if (owner) {
186+
owners.set(internal, owner);
187+
}
188+
if (prevInternalHook) prevInternalHook(internal, vnode);
189+
};
190+
162191
o._diff = o.__b = (internal: Internal, vnode: VNodeV11) => {
163192
if (internal.flags & TYPE_COMPONENT) {
164193
timings.start.set(internal, performance.now());
165194
const name = getDisplayName(internal, config);
166195
recordMark(`${name}_diff`);
167196

197+
const internalId = getVNodeId(internal);
198+
const vnodeId = getVNodeId(vnode);
199+
if (internalId !== vnodeId) {
200+
const owner = vnodeIdToOwner.get(internalId);
201+
if (owner) {
202+
vnodeIdToOwner.set(vnodeId, owner);
203+
}
204+
vnodeIdToOwner.delete(internalId);
205+
}
206+
168207
if (profiler.captureRenderReasons) {
169208
if (internal === null) {
170209
if (vnode !== null) {
@@ -182,8 +221,23 @@ export function setupOptionsV11(
182221
if (prevBeforeDiff != null) prevBeforeDiff(internal);
183222
};
184223

224+
o._render = o.__r = (internal: Internal) => {
225+
if (
226+
!skipEffects &&
227+
internal.flags & TYPE_COMPONENT &&
228+
internal.type !== config.Fragment
229+
) {
230+
ownerStack.push(internal);
231+
}
232+
if (prevRender != null) prevRender(internal);
233+
};
234+
185235
options.diffed = internal => {
186236
if (internal.flags & TYPE_COMPONENT) {
237+
if (internal.type !== config.Fragment) {
238+
ownerStack.pop();
239+
}
240+
187241
timings.end.set(internal, performance.now());
188242
endMark(getDisplayName(internal, config));
189243

@@ -221,6 +275,7 @@ export function setupOptionsV11(
221275
}
222276
}
223277

278+
ownerStack = [];
224279
renderer.onCommit(internal, owners, timings, renderReasons);
225280

226281
if (profiler.captureRenderReasons) {
@@ -231,6 +286,8 @@ export function setupOptionsV11(
231286

232287
options.unmount = internal => {
233288
if (prevBeforeUnmount) prevBeforeUnmount(internal);
289+
vnodeIdToOwner.delete(getVNodeId(internal));
290+
owners.delete(internal);
234291
timings.start.delete(internal);
235292
timings.end.delete(internal);
236293
renderer.onUnmount(internal);
@@ -240,10 +297,13 @@ export function setupOptionsV11(
240297
return () => {
241298
options.unmount = prevBeforeUnmount;
242299
o._commit = o.__c = prevCommitRoot;
243-
options.diffed = prevAfterDiff;
244300
o._diff = o.__b = prevBeforeDiff;
301+
o._render = o.__r = prevRender;
302+
options.diffed = prevAfterDiff;
245303
options._internal = prevVNodeHook;
246304
o._hook = o.__h = prevHook;
305+
o.vnode = prevVNodeHook;
306+
o._internal = o.__i = prevInternalHook;
247307
options.useDebugValue = prevUseDebugValue;
248308
};
249309
}

0 commit comments

Comments
 (0)