From c00768442a3c63d1881d670842014f4e1773faee Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 15 Jun 2021 11:59:47 +1000 Subject: [PATCH] chat-fe: improve render performance --- .../src/views/apps/chat/ChatResource.tsx | 12 +++++---- .../apps/chat/components/ChatMessage.tsx | 25 +++++++++---------- .../views/apps/chat/components/ChatPane.tsx | 10 +++++--- .../views/apps/chat/components/ChatWindow.tsx | 25 +++++-------------- 4 files changed, 31 insertions(+), 41 deletions(-) diff --git a/pkg/interface/src/views/apps/chat/ChatResource.tsx b/pkg/interface/src/views/apps/chat/ChatResource.tsx index f158ae6787..5a80838bf4 100644 --- a/pkg/interface/src/views/apps/chat/ChatResource.tsx +++ b/pkg/interface/src/views/apps/chat/ChatResource.tsx @@ -86,7 +86,7 @@ const ChatResource = (props: ChatResourceProps): ReactElement => { ); return `${url}\n~${msg.author}: `; }, - [association] + [association.resource] ); const isAdmin = useMemo( @@ -107,7 +107,7 @@ const ChatResource = (props: ChatResourceProps): ReactElement => { if (newer) { const index = graph.peekLargest()?.[0]; if (!index) { - return true; + return false; } await getYoungerSiblings( ship, @@ -119,10 +119,12 @@ const ChatResource = (props: ChatResourceProps): ReactElement => { } else { const index = graph.peekSmallest()?.[0]; if (!index) { - return true; + return false; } await getOlderSiblings(ship, name, pageSize, `/${index.toString()}`); - const done = expectedSize !== getCurrGraphSize(ship.slice(1), name); + const currSize = getCurrGraphSize(ship.slice(1), name); + console.log(currSize); + const done = expectedSize !== currSize; return done; } }, [graph, resource]); @@ -144,7 +146,7 @@ const ChatResource = (props: ChatResourceProps): ReactElement => { const getPermalink = useCallback( (index: BigInteger) => getPermalinkForGraph(association.group, resource, `/${index.toString()}`), - [association] + [association.resource] ); if (!graph) { diff --git a/pkg/interface/src/views/apps/chat/components/ChatMessage.tsx b/pkg/interface/src/views/apps/chat/components/ChatMessage.tsx index 83a4a690e5..e79aadc251 100644 --- a/pkg/interface/src/views/apps/chat/components/ChatMessage.tsx +++ b/pkg/interface/src/views/apps/chat/components/ChatMessage.tsx @@ -16,7 +16,7 @@ import { cite, daToUnix, useHovering, useShowNickname, uxToHex } from '~/logic/lib/util'; import { useContact } from '~/logic/state/contact'; -import useLocalState from '~/logic/state/local'; +import { useDark } from '~/logic/state/join'; import useSettingsState, { selectCalmState } from '~/logic/state/settings'; import { Dropdown } from '~/views/components/Dropdown'; import ProfileOverlay from '~/views/components/ProfileOverlay'; @@ -53,16 +53,13 @@ export const DayBreak = ({ when, shimTop = false }: DayBreakProps) => ( ); -export const MessageAuthor = ({ +export const MessageAuthor = React.memo(({ timestamp, msg, showOurContact, ...props }) => { - const osDark = useLocalState(state => state.dark); - - const theme = useSettingsState(s => s.display.theme); - const dark = theme === 'dark' || (theme === 'auto' && osDark); + const dark = useDark(); let contact: Contact | null = useContact(`~${msg.author}`); const date = daToUnix(bigInt(msg.index.split('/').reverse()[0])); @@ -177,7 +174,8 @@ export const MessageAuthor = ({ ); -}; +}); +MessageAuthor.displayName = 'MessageAuthor'; type MessageProps = { timestamp: string; timestampHover: boolean; } & Pick @@ -392,6 +390,7 @@ interface ChatMessageProps { showOurContact: boolean; onDelete?: () => void; } +const emptyCallback = () => {}; function ChatMessage(props: ChatMessageProps) { let { highlighted } = props; @@ -416,10 +415,10 @@ function ChatMessage(props: ChatMessageProps) { ); } - const onReply = props?.onReply ?? (() => {}); - const onDelete = props?.onDelete ?? (() => {}); - const transcluded = props?.transcluded ?? 0; - const renderSigil = props.renderSigil ?? (Boolean(nextMsg && msg.author !== nextMsg.author) || + const onReply = props?.onReply || emptyCallback; + const onDelete = props?.onDelete || emptyCallback; + const transcluded = props?.transcluded || 0; + const renderSigil = props.renderSigil || (Boolean(nextMsg && msg.author !== nextMsg.author) || !nextMsg ); @@ -509,9 +508,9 @@ function ChatMessage(props: ChatMessageProps) { ); } -export default React.forwardRef((props: Omit, ref: any) => ( +export default React.memo(React.forwardRef((props: Omit, ref: any) => ( -)); +))); export const MessagePlaceholder = ({ height, diff --git a/pkg/interface/src/views/apps/chat/components/ChatPane.tsx b/pkg/interface/src/views/apps/chat/components/ChatPane.tsx index 75dec04fcf..bd2f340907 100644 --- a/pkg/interface/src/views/apps/chat/components/ChatPane.tsx +++ b/pkg/interface/src/views/apps/chat/components/ChatPane.tsx @@ -6,7 +6,7 @@ import React, { ReactElement, useCallback, useEffect, useRef, useState } from 'r import { useFileDrag } from '~/logic/lib/useDrag'; import { useLocalStorageState } from '~/logic/lib/useLocalStorageState'; import { useOurContact } from '~/logic/state/contact'; -import useGraphState from '~/logic/state/graph'; +import { useGraphTimesent } from '~/logic/state/graph'; import ShareProfile from '~/views/apps/chat/components/ShareProfile'; import { Loading } from '~/views/components/Loading'; import SubmitDragger from '~/views/components/SubmitDragger'; @@ -77,7 +77,7 @@ export function ChatPane(props: ChatPaneProps): ReactElement { promptShare = [], fetchMessages } = props; - const graphTimesentMap = useGraphState(state => state.graphTimesentMap); + const graphTimesentMap = useGraphTimesent(id); const ourContact = useOurContact(); const chatInput = useRef(); @@ -88,7 +88,7 @@ export function ChatPane(props: ChatPaneProps): ReactElement { } (chatInput.current as NakedChatInput)?.uploadFiles(files); }, - [chatInput.current] + [chatInput] ); const { bind, dragging } = useFileDrag(onFileDrag); @@ -147,7 +147,7 @@ export function ChatPane(props: ChatPaneProps): ReactElement { graphSize={graph.size} unreadCount={unreadCount} showOurContact={promptShare.length === 0 && !showBanner} - pendingSize={Object.keys(graphTimesentMap[id] || {}).length} + pendingSize={Object.keys(graphTimesentMap).length} onReply={onReply} onDelete={onDelete} dismissUnread={dismissUnread} @@ -170,3 +170,5 @@ export function ChatPane(props: ChatPaneProps): ReactElement { ); } + +ChatPane.whyDidYouRender = true; diff --git a/pkg/interface/src/views/apps/chat/components/ChatWindow.tsx b/pkg/interface/src/views/apps/chat/components/ChatWindow.tsx index b650502d62..377aeac0a5 100644 --- a/pkg/interface/src/views/apps/chat/components/ChatWindow.tsx +++ b/pkg/interface/src/views/apps/chat/components/ChatWindow.tsx @@ -6,7 +6,7 @@ import { import bigInt, { BigInteger } from 'big-integer'; import React, { Component } from 'react'; import VirtualScroller from '~/views/components/VirtualScroller'; -import ChatMessage, { MessagePlaceholder } from './ChatMessage'; +import ChatMessage from './ChatMessage'; import UnreadNotice from './UnreadNotice'; const IDLE_THRESHOLD = 64; @@ -57,7 +57,7 @@ class ChatWindow extends Component< this.state = { fetchPending: false, idle: true, - initialized: false, + initialized: true, unreadIndex: bigInt.zero }; @@ -72,14 +72,10 @@ class ChatWindow extends Component< componentDidMount() { this.calculateUnreadIndex(); - setTimeout(() => { - this.setState({ initialized: true }, () => { - if(this.props.scrollTo) { - this.virtualList!.scrollLocked = false; - this.virtualList!.scrollToIndex(this.props.scrollTo); - } - }); - }, this.INITIALIZATION_MAX_TIME); + if(this.props.scrollTo) { + this.virtualList!.scrollLocked = false; + this.virtualList!.scrollToIndex(this.props.scrollTo); + } } calculateUnreadIndex() { @@ -205,15 +201,6 @@ class ChatWindow extends Component< ); } - if (!this.state.initialized) { - return ( - - ); - } const isPending: boolean = 'pending' in msg && Boolean(msg.pending); const isLastMessage = index.eq( graph.peekLargest()?.[0] ?? bigInt.zero