From 0f80ae91bee761a2c6edd1e57be84c2742ec9240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Tue, 28 Jan 2025 06:18:46 -0800 Subject: [PATCH] Throw an error when calling root.render outside of a task Summary: Changelog: [internal] I was adding a benchmark for rendering thousands of views and it was surprisingly fast, until I realized I wasn't wrapping the call to `root.render` in `runTask`, which means the benchmark wasn't really doing the rendering, only scheduling a microtask that was never executed. This is a safety mechanism to prevent those mistakes. Differential Revision: D68771170 --- .../src/__tests__/Fantom-itest.js | 16 ++++++++++++++++ packages/react-native-fantom/src/index.js | 8 +++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/react-native-fantom/src/__tests__/Fantom-itest.js b/packages/react-native-fantom/src/__tests__/Fantom-itest.js index 3eb82e160c524d..46b0304d3ca53b 100644 --- a/packages/react-native-fantom/src/__tests__/Fantom-itest.js +++ b/packages/react-native-fantom/src/__tests__/Fantom-itest.js @@ -155,6 +155,22 @@ describe('Fantom', () => { }, ); }); + + it('throws when trying to render a root outside of a task', () => { + const root = Fantom.createRoot(); + + expect(() => { + root.render(); + }).toThrow( + 'Unexpected call to `render` outside of the event loop. Please call `render` within a `runTask` callback.', + ); + + expect(() => { + Fantom.runTask(() => { + root.render(); + }); + }).not.toThrow(); + }); }); describe('getRenderedOutput', () => { diff --git a/packages/react-native-fantom/src/index.js b/packages/react-native-fantom/src/index.js index 327227d743bfd6..ddca12d3264e33 100644 --- a/packages/react-native-fantom/src/index.js +++ b/packages/react-native-fantom/src/index.js @@ -57,7 +57,13 @@ class Root { globalSurfaceIdCounter += 10; } - render(element: MixedElement) { + render(element: MixedElement): void { + if (!flushingQueue) { + throw new Error( + 'Unexpected call to `render` outside of the event loop. Please call `render` within a `runTask` callback.', + ); + } + if (!this.#hasRendered) { NativeFantom.startSurface( this.#surfaceId,