diff --git a/.changeset/green-plums-wave.md b/.changeset/green-plums-wave.md new file mode 100644 index 0000000000..c3c438abb8 --- /dev/null +++ b/.changeset/green-plums-wave.md @@ -0,0 +1,5 @@ +--- +"@lynx-js/react": patch +--- + +Avoid registering lifecycle refs for main-thread functions (MTF) that have not received an `execId` during `renderPage()` first-screen binding. diff --git a/packages/react/worklet-runtime/__test__/observers.test.js b/packages/react/worklet-runtime/__test__/observers.test.js new file mode 100644 index 0000000000..1bea337d47 --- /dev/null +++ b/packages/react/worklet-runtime/__test__/observers.test.js @@ -0,0 +1,53 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { onWorkletCtxUpdate } from '../src/bindings/observers'; +import { initWorklet } from '../src/workletRuntime'; + +beforeEach(() => { + globalThis.SystemInfo = { + lynxSdkVersion: '2.16', + }; + initWorklet(); +}); + +afterEach(() => { + delete globalThis.lynxWorkletImpl; +}); + +describe('MTFObservers', () => { + it('should not add a lifecycle ref when execId is missing for an MTF', () => { + const addRef = vi.fn(); + globalThis.lynxWorkletImpl._jsFunctionLifecycleManager = { + addRef, + }; + + onWorkletCtxUpdate( + { + _wkltId: 'ctx1', + }, + undefined, + false, + 'element', + ); + + expect(addRef).not.toHaveBeenCalled(); + }); + + it('should add a lifecycle ref when execId exists for an MTF', () => { + const addRef = vi.fn(); + globalThis.lynxWorkletImpl._jsFunctionLifecycleManager = { + addRef, + }; + const mtf = { + _wkltId: 'ctx1', + _execId: 8, + }; + + onWorkletCtxUpdate(mtf, undefined, false, 'element'); + + expect(addRef).toHaveBeenCalledWith(8, mtf); + }); +}); diff --git a/packages/react/worklet-runtime/src/bindings/observers.ts b/packages/react/worklet-runtime/src/bindings/observers.ts index 5f59e2648b..7f39ea9f30 100644 --- a/packages/react/worklet-runtime/src/bindings/observers.ts +++ b/packages/react/worklet-runtime/src/bindings/observers.ts @@ -18,7 +18,9 @@ export function onWorkletCtxUpdate( isFirstScreen: boolean, element: ElementNode, ): void { - globalThis.lynxWorkletImpl?._jsFunctionLifecycleManager?.addRef(worklet._execId!, worklet); + if (worklet._execId !== undefined) { + globalThis.lynxWorkletImpl?._jsFunctionLifecycleManager?.addRef(worklet._execId, worklet); + } if (isFirstScreen && oldWorklet) { globalThis.lynxWorkletImpl?._hydrateCtx(worklet, oldWorklet); }