fix(bug,perf): poll first-vote race, stale timeline ref, lazy GifPicker/EmojiBoard, focusItem timer leak, RoomNavItem memo

BUG-18: clearTimeout cleanup in focusItem useLayoutEffect prevents leaked timers
BUG-24: Room timeline listener catches first poll vote before Relations object exists
BUG-25: Use timelineRef.current in handleOpenEvent to prevent stale index on rapid navigation
Perf-6: React.lazy + Suspense for GifPicker and EmojiBoard (initial bundle -114 kB)
Perf-7: React.memo on RoomNavItem to prevent re-renders on unrelated state

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lotus Bot
2026-05-20 21:39:35 -04:00
parent 71791e46f6
commit ee7eabd2c4
4 changed files with 32 additions and 10 deletions
+7 -6
View File
@@ -30,7 +30,7 @@ import {
} from 'folds';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { GifPicker } from '../../components/GifPicker';
const GifPicker = React.lazy(() => import('../../components/GifPicker').then((m) => ({ default: m.GifPicker })));
import { useClientConfig } from '../../hooks/useClientConfig';
import {
CustomEditor,
@@ -56,7 +56,8 @@ import {
trimCommand,
getMentions,
} from '../../components/editor';
import { EmojiBoard, EmojiBoardTab } from '../../components/emoji-board';
import { EmojiBoardTab } from '../../components/emoji-board/types';
const EmojiBoard = React.lazy(() => import('../../components/emoji-board').then((m) => ({ default: m.EmojiBoard })));
import { UseStateProvider } from '../../components/UseStateProvider';
import {
TUploadContent,
@@ -690,7 +691,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
: emojiBtnRef.current?.getBoundingClientRect() ?? undefined
}
content={
<EmojiBoard
<React.Suspense fallback={null}><EmojiBoard
tab={emojiBoardTab}
onTabChange={setEmojiBoardTab}
imagePackRooms={imagePackRooms}
@@ -707,7 +708,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
return t;
});
}}
/>
/></React.Suspense>
}
>
{!hideStickerBtn && (
@@ -758,11 +759,11 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
: undefined
}
content={
<GifPicker
<React.Suspense fallback={null}><GifPicker
apiKey={gifApiKey}
onSelect={handleGifSelect}
requestClose={() => setGifOpen(false)}
/>
/></React.Suspense>
}
>
<IconButton