fix: memoize selected conversation props to avoid unneeded rerenders

This commit is contained in:
Audric Ackermann 2023-06-27 11:08:00 +02:00
parent 524debb307
commit dc3e8450e9
9 changed files with 65 additions and 54 deletions

View file

@ -36,6 +36,7 @@
},
"scripts": {
"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:watch": "yarn clean && yarn protobuf && yarn update-git-info && yarn sass && yarn build:workers && tsc -w",
"build:workers": "yarn worker:utils && yarn worker:libsession",

View file

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

View file

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

View file

@ -31,7 +31,11 @@ import { ToastUtils } from '../../../session/utils';
import { ReduxConversationType } from '../../../state/ducks/conversations';
import { removeAllStagedAttachmentsInConversation } from '../../../state/ducks/stagedAttachments';
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 { Flex } from '../../basic/Flex';
import { CaptionEditor } from '../../CaptionEditor';
@ -53,7 +57,6 @@ import styled from 'styled-components';
import { FixedBaseEmoji } from '../../../types/Reaction';
import {
getSelectedCanWrite,
getSelectedConversation,
getSelectedConversationKey,
} from '../../../state/selectors/selectedConversation';
import { SettingsKey } from '../../../data/settings-key';

View file

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

View file

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

View file

@ -31,7 +31,7 @@ import { getIntl } from './user';
import { filter, isEmpty, isNumber, pick, sortBy } from 'lodash';
import { MessageReactsSelectorProps } from '../../components/conversation/message/message-content/MessageReactions';
import { getSelectedConversation, getSelectedConversationKey } from './selectedConversation';
import { getSelectedConversationKey } from './selectedConversation';
import { getModeratorsOutsideRedux } from './sogsRoomInfo';
export const getConversations = (state: StateType): ConversationsStateType => state.conversations;
@ -626,6 +626,17 @@ export const isFirstUnreadMessageIdAbove = createSelector(
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
export const getMessagePropsByMessageId = createSelector(

View file

@ -3,9 +3,9 @@ import { useSelector } from 'react-redux';
import { ConversationTypeEnum, isOpenOrClosedGroup } from '../../models/conversationAttributes';
import { PubKey } from '../../session/types';
import { UserUtils } from '../../session/utils';
import { ReduxConversationType } from '../ducks/conversations';
import { StateType } from '../reducer';
import { getCanWrite, getModerators, getSubscriberCount } from './sogsRoomInfo';
import { getSelectedConversation } from './conversations';
/**
* Returns the formatted text for notification setting.
@ -58,11 +58,6 @@ export const getSelectedConversationKey = (state: StateType): string | undefined
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.
*/

View file

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