From 05d71dd163e93b5573dae234f3933d84c71b8aaa Mon Sep 17 00:00:00 2001 From: duckietm Date: Thu, 28 May 2026 13:46:44 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=86=99=20Small=20fix=20for=20the=20naviga?= =?UTF-8?q?tor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This mirrors what the old god-hook used to do and what the rest of the codebase still uses for everything else. The TanStack one-shot listener pattern (awaitNitroResponse registers a listener, awaits one matching response, removes itself) is fragile against renderer-bundle quirks — the parser fires but the listener never matches, so the promise never resolves and query.data stays undefined forever. That's exactly the symptom you saw: server logs show the response arriving, client UI stays blank. --- src/hooks/navigator/useNavigatorSearch.ts | 66 +++++++++++------------ 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/src/hooks/navigator/useNavigatorSearch.ts b/src/hooks/navigator/useNavigatorSearch.ts index b120001..ab3744d 100644 --- a/src/hooks/navigator/useNavigatorSearch.ts +++ b/src/hooks/navigator/useNavigatorSearch.ts @@ -1,47 +1,45 @@ -import { FlatCreatedEvent, NavigatorSearchComposer, NavigatorSearchEvent, - NavigatorSearchResultSet, RoomSettingsUpdatedEvent } from '@nitrots/nitro-renderer'; -import { useNitroEventInvalidator, useNitroQuery } from '../../api/nitro-query'; +import { NavigatorSearchComposer, NavigatorSearchEvent, NavigatorSearchResultSet } from '@nitrots/nitro-renderer'; +import { useEffect, useState } from 'react'; +import { SendMessageComposer } from '../../api'; +import { useMessageEvent } from '../events'; import { useNavigatorUiStore } from './navigatorUiStore'; -const SEARCH_BASE_KEY = [ 'navigator', 'search' ] as const; -/** - * TanStack Query wrapper for navigator search. - * - * Cache key: ['navigator', 'search', tabCode, filter] - * - Fires NavigatorSearchComposer(tabCode, filter) on miss. - * - Listens for NavigatorSearchEvent and resolves with the result. - * - accept-filter: rejects events whose result.code !== tabCode (defends - * against server-side cross-tab pushes resolving the wrong query slot). - * - Disabled when tabCode is '' (initial state, before metadata arrives). - * - Invalidates on FlatCreatedEvent (new room created) and - * RoomSettingsUpdatedEvent (room renamed / settings changed). - */ export const useNavigatorSearch = () => { const tabCode = useNavigatorUiStore(s => s.currentTabCode); const filter = useNavigatorUiStore(s => s.currentFilter); - const query = useNitroQuery({ - key: [ ...SEARCH_BASE_KEY, tabCode, filter ], - request: () => new NavigatorSearchComposer(tabCode, filter), - parser: NavigatorSearchEvent, - select: e => e.getParser()?.result ?? null, - accept: e => - { - const result = e.getParser()?.result; - return !!result && result.code === tabCode; - }, - enabled: !!tabCode, - staleTime: 30_000 + const [ searchResult, setSearchResult ] = useState(null); + const [ isFetching, setIsFetching ] = useState(false); + + useEffect(() => + { + if(!tabCode) return; + + setIsFetching(true); + SendMessageComposer(new NavigatorSearchComposer(tabCode, filter)); + }, [ tabCode, filter ]); + + useMessageEvent(NavigatorSearchEvent, event => + { + const result = event.getParser()?.result; + if(!result) return; + + if(tabCode && result.code !== tabCode) return; + + setSearchResult(result); + setIsFetching(false); }); - useNitroEventInvalidator(FlatCreatedEvent, [ ...SEARCH_BASE_KEY ]); - useNitroEventInvalidator(RoomSettingsUpdatedEvent, [ ...SEARCH_BASE_KEY ]); - return { - searchResult: query.data ?? null, - isFetching: query.isFetching, - refetch: query.refetch + searchResult, + isFetching, + refetch: () => + { + if(!tabCode) return; + setIsFetching(true); + SendMessageComposer(new NavigatorSearchComposer(tabCode, filter)); + } }; };