From 7b00e471ad2ceede483848179220f9af0187c07d Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Thu, 15 Jul 2021 01:32:24 +0300 Subject: [PATCH] [Perf] Chat List: Some optimizations --- src/components/left/main/ChatList.tsx | 12 ++++++++---- src/lib/teact/teact.ts | 22 +++++++++++++++++++--- src/modules/reducers/chats.ts | 16 ++++++++++++---- src/modules/reducers/users.ts | 17 ++++++++++++----- 4 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/components/left/main/ChatList.tsx b/src/components/left/main/ChatList.tsx index 9e739168a..9c4149902 100644 --- a/src/components/left/main/ChatList.tsx +++ b/src/components/left/main/ChatList.tsx @@ -90,11 +90,15 @@ const ChatList: FC = ({ const prevOrderById = usePrevious(orderById); - const orderDiffById = orderById && prevOrderById - ? mapValues(orderById, (order, id) => { + const orderDiffById = useMemo(() => { + if (!orderById || !prevOrderById) { + return {}; + } + + return mapValues(orderById, (order, id) => { return order - (prevOrderById[id] !== undefined ? prevOrderById[id] : Infinity); - }) - : {}; + }); + }, [orderById, prevOrderById]); const loadMoreOfType = useCallback(() => { loadMoreChats({ listType: folderType === 'archived' ? 'archived' : 'active' }); diff --git a/src/lib/teact/teact.ts b/src/lib/teact/teact.ts index 21a770d72..c93fe9334 100644 --- a/src/lib/teact/teact.ts +++ b/src/lib/teact/teact.ts @@ -85,8 +85,14 @@ interface ComponentInstance { onUpdate?: () => void; } -export type VirtualElement = VirtualElementEmpty | VirtualElementText | VirtualElementTag | VirtualElementComponent; -export type VirtualRealElement = VirtualElementTag | VirtualElementComponent; +export type VirtualElement = + VirtualElementEmpty + | VirtualElementText + | VirtualElementTag + | VirtualElementComponent; +export type VirtualRealElement = + VirtualElementTag + | VirtualElementComponent; export type VirtualElementChildren = VirtualElement[]; const Fragment = Symbol('Fragment'); @@ -545,7 +551,7 @@ export function useLayoutEffect(effect: () => Function | void, dependencies?: an return useLayoutEffectBase(onTickEnd, effect, dependencies); } -export function useMemo(resolver: () => T, dependencies: any[]): T { +export function useMemo(resolver: () => T, dependencies: any[], debugKey?: string): T { const { cursor, byCursor } = renderingInstance.hooks.memos; let { current } = byCursor[cursor] || {}; @@ -553,6 +559,16 @@ export function useMemo(resolver: () => T, dependencies: any[]): byCursor[cursor] === undefined || dependencies.some((dependency, i) => dependency !== byCursor[cursor].dependencies[i]) ) { + if (DEBUG && debugKey) { + // eslint-disable-next-line no-console + console.log( + `[Teact.useMemo] ${renderingInstance.name} (${debugKey}): Update is caused by:`, + byCursor[cursor] + ? getUnequalProps(dependencies, byCursor[cursor].dependencies).join(', ') + : '[first render]', + ); + } + current = resolver(); } diff --git a/src/modules/reducers/chats.ts b/src/modules/reducers/chats.ts index ba6d4c5f9..f6a63491c 100644 --- a/src/modules/reducers/chats.ts +++ b/src/modules/reducers/chats.ts @@ -100,20 +100,28 @@ export function updateChats(global: GlobalState, updatedById: Record): GlobalState { const { byId } = global.chats; + let isAdded = false; + const addedChats = Object.keys(addedById).map(Number).reduce>((acc, id) => { if (!byId[id] || (byId[id].isMin && !addedById[id].isMin)) { const updatedChat = getUpdatedChat(global, id, addedById[id]); if (updatedChat) { acc[id] = updatedChat; + + if (!isAdded) { + isAdded = true; + } } } return acc; }, {}); - global = replaceChats(global, { - ...global.chats.byId, - ...addedChats, - }); + if (isAdded) { + global = replaceChats(global, { + ...global.chats.byId, + ...addedChats, + }); + } return global; } diff --git a/src/modules/reducers/users.ts b/src/modules/reducers/users.ts index 94d1f6419..c4962d42a 100644 --- a/src/modules/reducers/users.ts +++ b/src/modules/reducers/users.ts @@ -91,23 +91,30 @@ export function updateUsers(global: GlobalState, updatedById: Record): GlobalState { const { byId } = global.users; + let isAdded = false; const addedUsers = Object.keys(addedById).map(Number).reduce>((acc, id) => { if (!byId[id] || (byId[id].isMin && !addedById[id].isMin)) { const updatedUser = getUpdatedUser(global, id, addedById[id]); if (updatedUser) { acc[id] = updatedUser; + + if (!isAdded) { + isAdded = true; + } } } return acc; }, {}); - global = updateContactList(global, Object.values(addedUsers)); + if (isAdded) { + global = replaceUsers(global, { + ...global.users.byId, + ...addedUsers, + }); - global = replaceUsers(global, { - ...global.users.byId, - ...addedUsers, - }); + global = updateContactList(global, Object.values(addedUsers)); + } return global; }