From c6ec887a21f129ba0ce0df6ed137cf4d31c20a5f Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Thu, 23 Jul 2026 07:20:34 +0200 Subject: [PATCH] fix(picker): declare the version hooks BEFORE the memos that list them as deps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit filteredComponents' new registryVersion dep evaluated in its useMemo deps array while the const was still in the temporal dead zone (declared further down the component) — 'Cannot access N before initialization', white screen on every page. Hooks moved up next to the registry declaration. --- .../src/components/ComponentPickerModal.tsx | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/frontend/src/components/ComponentPickerModal.tsx b/frontend/src/components/ComponentPickerModal.tsx index 670549aa..514e6434 100644 --- a/frontend/src/components/ComponentPickerModal.tsx +++ b/frontend/src/components/ComponentPickerModal.tsx @@ -141,6 +141,22 @@ export const ComponentPickerModal: React.FC = ({ 'all', ); const [registry] = useState(() => ComponentRegistry.getInstance()); + // Late-overlay registrations must re-render an already-mounted picker: + // the @pro import is dynamic, so boards/components can register AFTER the + // first render. Without these subscriptions the memos below freeze on the + // pre-registration state (boards missing, ONLINE ads instead of the real + // components - and which one you got depended on a reload race). + const proBoardsVersion = useSyncExternalStore( + subscribeProBoards, + getProBoardsVersion, + getProBoardsVersion, + ); + const registryVersion = useSyncExternalStore( + registry.subscribe, + registry.getVersion, + registry.getVersion, + ); + const [isLoading, setIsLoading] = useState(true); // Floating datasheet popover shown on card hover. A single instance is // driven from here so only one panel ever exists in the DOM. Hiding is @@ -212,21 +228,6 @@ export const ComponentPickerModal: React.FC = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [searchQuery, selectedCategory, registry, isLoading, registryVersion]); - // Late-overlay registrations must re-render an already-mounted picker: - // the @pro import is dynamic, so boards/components can register AFTER the - // first render. Without these subscriptions the memos below freeze on the - // pre-registration state (boards missing, ONLINE ads instead of the real - // components - and which one you got depended on a reload race). - const proBoardsVersion = useSyncExternalStore( - subscribeProBoards, - getProBoardsVersion, - getProBoardsVersion, - ); - const registryVersion = useSyncExternalStore( - registry.subscribe, - registry.getVersion, - registry.getVersion, - ); // Boards list: static OSS kinds + overlay-registered boards (proBoardRegistry). const allBoards = useMemo(() => {