fix: memoize selected conversation props to avoid unneeded rerenders

pull/2795/head
Audric Ackermann 2 years ago
parent 524debb307
commit dc3e8450e9

@ -36,6 +36,7 @@
}, },
"scripts": { "scripts": {
"start-prod": "cross-env NODE_ENV=production NODE_APP_INSTANCE=devprod$MULTI electron .", "start-prod": "cross-env NODE_ENV=production NODE_APP_INSTANCE=devprod$MULTI electron .",
"start-dev": "cross-env NODE_ENV=development NODE_APP_INSTANCE=devprod$MULTI electron .",
"build-everything": "yarn clean && yarn protobuf && yarn update-git-info && yarn sass && tsc && yarn build:workers", "build-everything": "yarn clean && yarn protobuf && yarn update-git-info && yarn sass && tsc && yarn build:workers",
"build-everything:watch": "yarn clean && yarn protobuf && yarn update-git-info && yarn sass && yarn build:workers && tsc -w", "build-everything:watch": "yarn clean && yarn protobuf && yarn update-git-info && yarn sass && yarn build:workers && tsc -w",
"build:workers": "yarn worker:utils && yarn worker:libsession", "build:workers": "yarn worker:utils && yarn worker:libsession",

@ -20,14 +20,6 @@ window.getEnvironment = () => config.environment;
window.getVersion = () => config.version; window.getVersion = () => config.version;
window.getAppInstance = () => config.appInstance; window.getAppInstance = () => config.appInstance;
const { SessionPasswordPrompt } = require('./ts/components/SessionPasswordPrompt');
window.Signal = {
Components: {
SessionPasswordPrompt,
},
};
window.clearLocalData = async () => { window.clearLocalData = async () => {
window.log.info('reset database'); window.log.info('reset database');
ipcRenderer.send('resetDatabase'); ipcRenderer.send('resetDatabase');

@ -17,12 +17,10 @@ import {
import { StateType } from '../../state/reducer'; import { StateType } from '../../state/reducer';
import { import {
getQuotedMessageToAnimate, getQuotedMessageToAnimate,
getSelectedConversation,
getSortedMessagesOfSelectedConversation, getSortedMessagesOfSelectedConversation,
} from '../../state/selectors/conversations'; } from '../../state/selectors/conversations';
import { import { getSelectedConversationKey } from '../../state/selectors/selectedConversation';
getSelectedConversation,
getSelectedConversationKey,
} from '../../state/selectors/selectedConversation';
import { SessionMessagesList } from './SessionMessagesList'; import { SessionMessagesList } from './SessionMessagesList';
import { TypingBubble } from './TypingBubble'; import { TypingBubble } from './TypingBubble';
import { ConversationMessageRequestButtons } from './MessageRequestButtons'; import { ConversationMessageRequestButtons } from './MessageRequestButtons';

@ -31,7 +31,11 @@ import { ToastUtils } from '../../../session/utils';
import { ReduxConversationType } from '../../../state/ducks/conversations'; import { ReduxConversationType } from '../../../state/ducks/conversations';
import { removeAllStagedAttachmentsInConversation } from '../../../state/ducks/stagedAttachments'; import { removeAllStagedAttachmentsInConversation } from '../../../state/ducks/stagedAttachments';
import { StateType } from '../../../state/reducer'; import { StateType } from '../../../state/reducer';
import { getMentionsInput, getQuotedMessage } from '../../../state/selectors/conversations'; import {
getMentionsInput,
getQuotedMessage,
getSelectedConversation,
} from '../../../state/selectors/conversations';
import { AttachmentUtil } from '../../../util'; import { AttachmentUtil } from '../../../util';
import { Flex } from '../../basic/Flex'; import { Flex } from '../../basic/Flex';
import { CaptionEditor } from '../../CaptionEditor'; import { CaptionEditor } from '../../CaptionEditor';
@ -53,7 +57,6 @@ import styled from 'styled-components';
import { FixedBaseEmoji } from '../../../types/Reaction'; import { FixedBaseEmoji } from '../../../types/Reaction';
import { import {
getSelectedCanWrite, getSelectedCanWrite,
getSelectedConversation,
getSelectedConversationKey, getSelectedConversationKey,
} from '../../../state/selectors/selectedConversation'; } from '../../../state/selectors/selectedConversation';
import { SettingsKey } from '../../../data/settings-key'; import { SettingsKey } from '../../../data/settings-key';

@ -497,35 +497,51 @@ async function getSeenMessagesByHashList(hashes: Array<string>): Promise<any> {
} }
async function removeAllMessagesInConversation(conversationId: string): Promise<void> { async function removeAllMessagesInConversation(conversationId: string): Promise<void> {
const startFunction = Date.now();
let start = Date.now(); let start = Date.now();
const messages = await getLastMessagesByConversation(conversationId, 50, false);
window.log.info(
`removeAllMessagesInConversation ${conversationId} ${messages.length} took ${Date.now() -
start}`
);
if (!messages.length) {
return;
}
// Note: It's very important that these models are fully hydrated because let messages;
// we need to delete all associated on-disk files along with the database delete. do {
// eslint-disable-next-line no-await-in-loop // Yes, we really want the await in the loop. We're deleting 500 at a
// time so we don't use too much memory.
start = Date.now(); // eslint-disable-next-line no-await-in-loop
for (let index = 0; index < messages.length; index++) { messages = await getLastMessagesByConversation(conversationId, 1000, false);
const message = messages.at(index); if (!messages.length) {
await message.cleanup(); return;
} }
window.log.info( window.log.info(
`removeAllMessagesInConversation messages.cleanup() ${conversationId} took ${Date.now() - `removeAllMessagesInConversation getLastMessagesByConversation ${conversationId} ${
start}ms` messages.length
); } took ${Date.now() - start}ms`
start = Date.now(); );
// Note: It's very important that these models are fully hydrated because
// we need to delete all associated on-disk files along with the database delete.
const ids = messages.map(message => message.id);
start = Date.now();
for (let index = 0; index < messages.length; index++) {
const message = messages.at(index);
// eslint-disable-next-line no-await-in-loop
await message.cleanup();
}
window.log.info(
`removeAllMessagesInConversation messages.cleanup() ${conversationId} took ${Date.now() -
start}ms`
);
start = Date.now();
// eslint-disable-next-line no-await-in-loop
await channels.removeMessagesByIds(ids);
window.log.info(
`removeAllMessagesInConversation: removeMessagesByIds ${conversationId} took ${Date.now() -
start}ms`
);
} while (messages.length);
// eslint-disable-next-line no-await-in-loop
await channels.removeAllMessagesInConversation(conversationId); await channels.removeAllMessagesInConversation(conversationId);
window.log.info( window.log.info(
`removeAllMessagesInConversation: ${conversationId} took ${Date.now() - start}ms` `removeAllMessagesInConversation: complete time ${conversationId} took ${Date.now() -
startFunction}ms`
); );
} }

@ -958,7 +958,6 @@ function removeMessagesByIds(ids: Array<string>, instance?: BetterSqlite3.Databa
} }
const start = Date.now(); const start = Date.now();
// TODO we might need to do the same thing as
assertGlobalInstanceOrInstance(instance) assertGlobalInstanceOrInstance(instance)
.prepare(`DELETE FROM ${MESSAGES_TABLE} WHERE id IN ( ${ids.map(() => '?').join(', ')} );`) .prepare(`DELETE FROM ${MESSAGES_TABLE} WHERE id IN ( ${ids.map(() => '?').join(', ')} );`)
.run(ids); .run(ids);
@ -974,11 +973,9 @@ function removeAllMessagesInConversation(
} }
const inst = assertGlobalInstanceOrInstance(instance); const inst = assertGlobalInstanceOrInstance(instance);
inst.transaction(() => { inst
inst .prepare(`DELETE FROM ${MESSAGES_TABLE} WHERE conversationId = $conversationId`)
.prepare(`DELETE FROM ${MESSAGES_TABLE} WHERE conversationId = $conversationId`) .run({ conversationId });
.run({ conversationId });
})();
} }
function getMessageIdsFromServerIds(serverIds: Array<string | number>, conversationId: string) { function getMessageIdsFromServerIds(serverIds: Array<string | number>, conversationId: string) {

@ -31,7 +31,7 @@ import { getIntl } from './user';
import { filter, isEmpty, isNumber, pick, sortBy } from 'lodash'; import { filter, isEmpty, isNumber, pick, sortBy } from 'lodash';
import { MessageReactsSelectorProps } from '../../components/conversation/message/message-content/MessageReactions'; import { MessageReactsSelectorProps } from '../../components/conversation/message/message-content/MessageReactions';
import { getSelectedConversation, getSelectedConversationKey } from './selectedConversation'; import { getSelectedConversationKey } from './selectedConversation';
import { getModeratorsOutsideRedux } from './sogsRoomInfo'; import { getModeratorsOutsideRedux } from './sogsRoomInfo';
export const getConversations = (state: StateType): ConversationsStateType => state.conversations; export const getConversations = (state: StateType): ConversationsStateType => state.conversations;
@ -626,6 +626,17 @@ export const isFirstUnreadMessageIdAbove = createSelector(
const getMessageId = (_whatever: any, id: string | undefined) => id; const getMessageId = (_whatever: any, id: string | undefined) => id;
/**
* A lot of our UI changes on the main panel need to happen quickly (composition box).
*/
export const getSelectedConversation = createSelector(
getConversationLookup,
getSelectedConversationKey,
(lookup, selectedConvo) => {
return selectedConvo ? lookup[selectedConvo] : undefined;
}
);
// tslint:disable: cyclomatic-complexity // tslint:disable: cyclomatic-complexity
export const getMessagePropsByMessageId = createSelector( export const getMessagePropsByMessageId = createSelector(

@ -3,9 +3,9 @@ import { useSelector } from 'react-redux';
import { ConversationTypeEnum, isOpenOrClosedGroup } from '../../models/conversationAttributes'; import { ConversationTypeEnum, isOpenOrClosedGroup } from '../../models/conversationAttributes';
import { PubKey } from '../../session/types'; import { PubKey } from '../../session/types';
import { UserUtils } from '../../session/utils'; import { UserUtils } from '../../session/utils';
import { ReduxConversationType } from '../ducks/conversations';
import { StateType } from '../reducer'; import { StateType } from '../reducer';
import { getCanWrite, getModerators, getSubscriberCount } from './sogsRoomInfo'; import { getCanWrite, getModerators, getSubscriberCount } from './sogsRoomInfo';
import { getSelectedConversation } from './conversations';
/** /**
* Returns the formatted text for notification setting. * Returns the formatted text for notification setting.
@ -58,11 +58,6 @@ export const getSelectedConversationKey = (state: StateType): string | undefined
return state.conversations.selectedConversation; return state.conversations.selectedConversation;
}; };
export const getSelectedConversation = (state: StateType): ReduxConversationType | undefined => {
const selected = getSelectedConversationKey(state);
return selected ? state.conversations.conversationLookup[selected] : undefined;
};
/** /**
* Returns true if the current conversation selected is a public group and false otherwise. * Returns true if the current conversation selected is a public group and false otherwise.
*/ */

@ -6,15 +6,13 @@ import { getHasOngoingCallWithFocusedConvo } from '../selectors/call';
import { import {
getIsSelectedConvoInitialLoadingInProgress, getIsSelectedConvoInitialLoadingInProgress,
getLightBoxOptions, getLightBoxOptions,
getSelectedConversation,
getSelectedMessageIds, getSelectedMessageIds,
getSortedMessagesOfSelectedConversation, getSortedMessagesOfSelectedConversation,
isMessageDetailView, isMessageDetailView,
isRightPanelShowing, isRightPanelShowing,
} from '../selectors/conversations'; } from '../selectors/conversations';
import { import { getSelectedConversationKey } from '../selectors/selectedConversation';
getSelectedConversation,
getSelectedConversationKey,
} from '../selectors/selectedConversation';
import { getStagedAttachmentsForCurrentConversation } from '../selectors/stagedAttachments'; import { getStagedAttachmentsForCurrentConversation } from '../selectors/stagedAttachments';
import { getTheme } from '../selectors/theme'; import { getTheme } from '../selectors/theme';
import { getOurNumber } from '../selectors/user'; import { getOurNumber } from '../selectors/user';

Loading…
Cancel
Save