fix(sidebar): favourite / low-priority changes move the room immediately
Home's categorisation memo keyed only on the room list, and nothing observed m.tag changes. The SDK emits RoomEvent.Tags on the room and re-emits it on the client (room.js addTags, sync.js reEmit); a small client-level hook bumps a version that the memo depends on. Fixes #20 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import { useEffect } from 'react';
|
||||
import { MatrixClient, RoomEvent } from 'matrix-js-sdk';
|
||||
import { useForceUpdate } from './useForceUpdate';
|
||||
|
||||
/**
|
||||
* Bumps a counter whenever any room's `m.tag` account data changes
|
||||
* (favourite/low-priority add or remove via `mx.setRoomTag`/`deleteRoomTag`).
|
||||
*
|
||||
* `RoomEvent.Tags` is emitted on the individual `Room` by `Room.addTags()`
|
||||
* (matrix-js-sdk `lib/models/room.js`) and re-emitted onto the `MatrixClient`
|
||||
* itself by the sync loop (`lib/sync.js`, the `client.reEmitter.reEmit(room, [...
|
||||
* RoomEvent.Tags ...])` call), so a single client-level listener here sees the
|
||||
* change for every room without needing to attach/detach a per-room listener.
|
||||
*
|
||||
* Consumers should add the returned counter to the deps of any memo that
|
||||
* derives favourite/low-priority categorisation from `room.tags`, so toggling
|
||||
* a tag moves the room immediately instead of waiting for an unrelated
|
||||
* re-render to pick up the mutated (but stale-looking) `Room` object.
|
||||
*/
|
||||
export const useRoomTagsVersion = (mx: MatrixClient): number => {
|
||||
const [version, bumpVersion] = useForceUpdate();
|
||||
|
||||
useEffect(() => {
|
||||
mx.on(RoomEvent.Tags, bumpVersion);
|
||||
return () => {
|
||||
mx.removeListener(RoomEvent.Tags, bumpVersion);
|
||||
};
|
||||
}, [mx, bumpVersion]);
|
||||
|
||||
return version;
|
||||
};
|
||||
@@ -79,6 +79,7 @@ import { UseStateProvider } from '../../../components/UseStateProvider';
|
||||
import { JoinAddressPrompt } from '../../../components/join-address-prompt';
|
||||
import { _RoomSearchParams } from '../../paths';
|
||||
import { getLocalRoomNamesContent } from '../../../hooks/useRoomMeta';
|
||||
import { useRoomTagsVersion } from '../../../hooks/useRoomTagsVersion';
|
||||
|
||||
type HomeMenuProps = {
|
||||
requestClose: () => void;
|
||||
@@ -253,6 +254,11 @@ export function Home() {
|
||||
const [homeRoomSort, setHomeRoomSort] = useSetting(settingsAtom, 'homeRoomSort');
|
||||
const roomToUnread = useAtomValue(roomToUnreadAtom);
|
||||
const [sortMenuAnchor, setSortMenuAnchor] = useState<RectCords>();
|
||||
// Bumped whenever any room's `m.tag` account data changes (favourite/low-priority
|
||||
// toggle via RoomNavItemMenu). Nothing else re-runs this memo on a tag change
|
||||
// (see useRoomTagsVersion.ts), so without this dep a room only moves section
|
||||
// once some unrelated event (e.g. an unread-count change) forces a re-render.
|
||||
const roomTagsVersion = useRoomTagsVersion(mx);
|
||||
|
||||
const { favoriteRooms, lowPriorityRooms, otherRooms } = useMemo(() => {
|
||||
const favs: string[] = [];
|
||||
@@ -269,7 +275,10 @@ export function Home() {
|
||||
}
|
||||
});
|
||||
return { favoriteRooms: favs, lowPriorityRooms: low, otherRooms: others };
|
||||
}, [mx, rooms]);
|
||||
// roomTagsVersion is a trigger-only counter, not read in the body; it forces
|
||||
// this memo to re-run whenever any room's tags change.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [mx, rooms, roomTagsVersion]);
|
||||
|
||||
const sortedFavoriteRooms = useMemo(() => {
|
||||
const isClosed = closedCategories.has(FAVORITES_CATEGORY_ID);
|
||||
|
||||
Reference in New Issue
Block a user