Prefer RoomStateEvent.Update where possible as it fires far less (#7878)

This commit is contained in:
Michael Telatynski 2022-02-24 14:39:25 +00:00 committed by GitHub
parent 36ae0ea49d
commit c257bc3f7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 223 additions and 190 deletions

View file

@ -15,11 +15,11 @@ limitations under the License.
*/
import { useCallback, useState } from "react";
import { MatrixClient } from "matrix-js-sdk/src/client";
import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/client";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Room } from "matrix-js-sdk/src/models/room";
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
import { useEventEmitter } from "./useEventEmitter";
import { useTypedEventEmitter } from "./useEventEmitter";
const tryGetContent = <T extends {}>(ev?: MatrixEvent) => ev ? ev.getContent<T>() : undefined;
@ -31,7 +31,7 @@ export const useAccountData = <T extends {}>(cli: MatrixClient, eventType: strin
if (event.getType() !== eventType) return;
setValue(event.getContent());
}, [eventType]);
useEventEmitter(cli, "accountData", handler);
useTypedEventEmitter(cli, ClientEvent.AccountData, handler);
return value || {} as T;
};
@ -44,7 +44,7 @@ export const useRoomAccountData = <T extends {}>(room: Room, eventType: string)
if (event.getType() !== eventType) return;
setValue(event.getContent());
}, [eventType]);
useEventEmitter(room, "Room.accountData", handler);
useTypedEventEmitter(room, RoomEvent.AccountData, handler);
return value || {} as T;
};

View file

@ -15,17 +15,29 @@ limitations under the License.
*/
import { useRef, useEffect, useState, useCallback } from "react";
import { ListenerMap, TypedEventEmitter } from "matrix-js-sdk/src/models/typed-event-emitter";
import type { EventEmitter } from "events";
type Handler = (...args: any[]) => void;
export function useTypedEventEmitter<
Events extends string,
Arguments extends ListenerMap<Events>,
>(
emitter: TypedEventEmitter<Events, Arguments>,
eventName: Events,
handler: Handler,
): void {
useEventEmitter(emitter, eventName, handler);
}
// Hook to wrap event emitter on and removeListener in hook lifecycle
export const useEventEmitter = (
export function useEventEmitter(
emitter: EventEmitter | undefined,
eventName: string | symbol,
handler: Handler,
) => {
): void {
// Create a ref that stores handler
const savedHandler = useRef(handler);
@ -52,15 +64,27 @@ export const useEventEmitter = (
},
[eventName, emitter], // Re-run if eventName or emitter changes
);
};
}
type Mapper<T> = (...args: any[]) => T;
export const useEventEmitterState = <T>(
export function useTypedEventEmitterState<
T,
Events extends string,
Arguments extends ListenerMap<Events>,
>(
emitter: TypedEventEmitter<Events, Arguments>,
eventName: Events,
fn: Mapper<T>,
): T {
return useEventEmitterState<T>(emitter, eventName, fn);
}
export function useEventEmitterState<T>(
emitter: EventEmitter | undefined,
eventName: string | symbol,
fn: Mapper<T>,
): T => {
): T {
const [value, setValue] = useState<T>(fn());
const handler = useCallback((...args: any[]) => {
setValue(fn(...args));
@ -69,4 +93,4 @@ export const useEventEmitterState = <T>(
useEffect(handler, [emitter]); // eslint-disable-line react-hooks/exhaustive-deps
useEventEmitter(emitter, eventName, handler);
return value;
};
}

View file

@ -18,19 +18,21 @@ import { useCallback, useState } from "react";
import { MatrixClient } from "matrix-js-sdk/src/client";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Room } from "matrix-js-sdk/src/models/room";
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { EventType } from "matrix-js-sdk/src/@types/event";
import { useEventEmitter } from "./useEventEmitter";
import { useTypedEventEmitter } from "./useEventEmitter";
// Hook to simplify watching whether a Matrix room is encrypted, returns undefined if room is undefined
export function useIsEncrypted(cli: MatrixClient, room?: Room): boolean | undefined {
const [isEncrypted, setIsEncrypted] = useState(room ? cli.isRoomEncrypted(room.roomId) : undefined);
const update = useCallback((event: MatrixEvent) => {
if (room && event.getType() === "m.room.encryption") {
if (room && event.getType() === EventType.RoomEncryption) {
setIsEncrypted(cli.isRoomEncrypted(room.roomId));
}
}, [cli, room]);
useEventEmitter(room ? room.currentState : undefined, "RoomState.events", update);
useTypedEventEmitter(room?.currentState, RoomStateEvent.Events, update);
return isEncrypted;
}

View file

@ -17,14 +17,15 @@ limitations under the License.
import { useState } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { throttle } from "lodash";
import { useEventEmitter } from "./useEventEmitter";
import { useTypedEventEmitter } from "./useEventEmitter";
// Hook to simplify watching Matrix Room joined members
export const useRoomMembers = (room: Room, throttleWait = 250) => {
const [members, setMembers] = useState<RoomMember[]>(room.getJoinedMembers());
useEventEmitter(room.currentState, "RoomState.members", throttle(() => {
useTypedEventEmitter(room.currentState, RoomStateEvent.Update, throttle(() => {
setMembers(room.getJoinedMembers());
}, throttleWait, { leading: true, trailing: true }));
return members;
@ -33,7 +34,7 @@ export const useRoomMembers = (room: Room, throttleWait = 250) => {
// Hook to simplify watching Matrix Room joined member count
export const useRoomMemberCount = (room: Room, throttleWait = 250) => {
const [count, setCount] = useState<number>(room.getJoinedMemberCount());
useEventEmitter(room.currentState, "RoomState.members", throttle(() => {
useTypedEventEmitter(room.currentState, RoomStateEvent.Update, throttle(() => {
setCount(room.getJoinedMemberCount());
}, throttleWait, { leading: true, trailing: true }));
return count;

View file

@ -16,9 +16,9 @@ limitations under the License.
import { useCallback, useEffect, useState } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import { RoomState } from "matrix-js-sdk/src/models/room-state";
import { RoomState, RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { useEventEmitter } from "./useEventEmitter";
import { useTypedEventEmitter } from "./useEventEmitter";
type Mapper<T> = (roomState: RoomState) => T;
const defaultMapper: Mapper<RoomState> = (roomState: RoomState) => roomState;
@ -36,7 +36,7 @@ export const useRoomState = <T extends any = RoomState>(
setValue(mapper(room.currentState));
}, [room, mapper]);
useEventEmitter(room?.currentState, "RoomState.events", update);
useTypedEventEmitter(room?.currentState, RoomStateEvent.Update, update);
useEffect(() => {
update();
return () => {

View file

@ -15,11 +15,11 @@ limitations under the License.
*/
import { MatrixClient } from "matrix-js-sdk/src/client";
import { User } from "matrix-js-sdk/src/models/user";
import { User, UserEvent } from "matrix-js-sdk/src/models/user";
import { useContext } from "react";
import MatrixClientContext from "../contexts/MatrixClientContext";
import { useEventEmitterState } from "./useEventEmitter";
import { useTypedEventEmitterState } from "./useEventEmitter";
import { Member } from "../components/views/right_panel/UserInfo";
import { useFeatureEnabled } from "./useSettings";
@ -29,10 +29,11 @@ const getStatusMessage = (cli: MatrixClient, user: Member): string => {
};
// Hook to simplify handling Matrix User status
export const useUserStatusMessage = (user?: Member): string => {
export const useUserStatusMessage = (member?: Member): string => {
const cli = useContext(MatrixClientContext);
const enabled = useFeatureEnabled("feature_custom_status");
return useEventEmitterState(enabled && getUser(cli, user), "User.unstable_statusMessage", () => {
const user = enabled ? getUser(cli, member) : undefined;
return useTypedEventEmitterState(user, UserEvent._UnstableStatusMessage, () => {
return getStatusMessage(cli, user);
});
};