web/roomlist,timeline: memoize rooms and messages

This commit is contained in:
Tulir Asokan 2024-10-21 22:10:40 +03:00
parent 52b4e2d6d1
commit aae6e7496c
3 changed files with 44 additions and 14 deletions

View file

@ -153,10 +153,14 @@ export class RoomStateStore {
} else if (memEvt.relation_type === "m.replace" && memEvt.relates_to) { } else if (memEvt.relation_type === "m.replace" && memEvt.relates_to) {
const editTarget = this.eventsByID.get(memEvt.relates_to) const editTarget = this.eventsByID.get(memEvt.relates_to)
if (editTarget?.last_edit_rowid === memEvt.rowid && !editTarget.last_edit) { if (editTarget?.last_edit_rowid === memEvt.rowid && !editTarget.last_edit) {
editTarget.last_edit = memEvt this.eventsByRowID.set(editTarget.rowid, {
editTarget.orig_content = editTarget.content ...editTarget,
editTarget.content = memEvt.content["m.new_content"] last_edit: memEvt,
editTarget.local_content = memEvt.local_content orig_content: editTarget.content,
content: memEvt.content["m.new_content"],
local_content: memEvt.local_content,
})
this.eventSubs.get(editTarget.event_id)?.notify()
} }
} }
this.eventsByRowID.set(memEvt.rowid, memEvt) this.eventsByRowID.set(memEvt.rowid, memEvt)

View file

@ -13,7 +13,7 @@
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import { use } from "react" import { memo, use, useLayoutEffect, useRef, useState } from "react"
import { getMediaURL } from "@/api/media.ts" import { getMediaURL } from "@/api/media.ts"
import type { RoomListEntry } from "@/api/statestore" import type { RoomListEntry } from "@/api/statestore"
import type { MemDBEvent, MemberEventContent } from "@/api/types" import type { MemDBEvent, MemberEventContent } from "@/api/types"
@ -26,7 +26,7 @@ export interface RoomListEntryProps {
hidden: boolean hidden: boolean
} }
function usePreviewText(evt?: MemDBEvent, senderMemberEvt?: MemDBEvent): [string, string] { function usePreviewText(evt?: MemDBEvent, senderMemberEvt?: MemDBEvent | null): [string, string] {
if (!evt) { if (!evt) {
return ["", ""] return ["", ""]
} }
@ -46,13 +46,13 @@ function usePreviewText(evt?: MemDBEvent, senderMemberEvt?: MemDBEvent): [string
return ["", ""] return ["", ""]
} }
const Entry = ({ room, setActiveRoom, isActive, hidden }: RoomListEntryProps) => { interface InnerProps {
room: RoomListEntry
}
const EntryInner = ({ room }: InnerProps) => {
const [previewText, croppedPreviewText] = usePreviewText(room.preview_event, room.preview_sender) const [previewText, croppedPreviewText] = usePreviewText(room.preview_event, room.preview_sender)
return <div return <>
className={`room-entry ${isActive ? "active" : ""} ${hidden ? "hidden" : ""}`}
onClick={setActiveRoom}
data-room-id={room.room_id}
>
<div className="room-entry-left"> <div className="room-entry-left">
<img loading="lazy" className="avatar room-avatar" src={getMediaURL(room.avatar)} alt=""/> <img loading="lazy" className="avatar room-avatar" src={getMediaURL(room.avatar)} alt=""/>
</div> </div>
@ -68,7 +68,33 @@ const Entry = ({ room, setActiveRoom, isActive, hidden }: RoomListEntryProps) =>
{room.unread_messages || room.unread_notifications || room.unread_highlights} {room.unread_messages || room.unread_notifications || room.unread_highlights}
</div> </div>
</div> : null} </div> : null}
</>
}
const Entry = ({ room, setActiveRoom, isActive, hidden }: RoomListEntryProps) => {
const [isVisible, setVisible] = useState(false)
const divRef = useRef<HTMLDivElement>(null)
useLayoutEffect(() => {
const div = divRef.current
if (!div) {
return
}
const listener = (evt: unknown) => {
if (!(evt as ContentVisibilityAutoStateChangeEvent).skipped) {
setVisible(true)
}
}
div.addEventListener("contentvisibilityautostatechange", listener)
return () => div.removeEventListener("contentvisibilityautostatechange", listener)
}, [])
return <div
ref={divRef}
className={`room-entry ${isActive ? "active" : ""} ${hidden ? "hidden" : ""}`}
onClick={setActiveRoom}
data-room-id={room.room_id}
>
{isVisible ? <EntryInner room={room}/> : null}
</div> </div>
} }
export default Entry export default memo(Entry)

View file

@ -136,4 +136,4 @@ const TimelineEvent = ({ room, evt, prevEvt, setReplyToRef }: TimelineEventProps
</> </>
} }
export default TimelineEvent export default React.memo(TimelineEvent)