Additional render optimizations
This commit is contained in:
parent
6343e7c902
commit
7a8363c7c8
4 changed files with 93 additions and 70 deletions
|
@ -1,9 +1,10 @@
|
||||||
// Copyright 2019-2021 Signal Messenger, LLC
|
// Copyright 2019-2021 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import { debounce, get, isNumber, pick } from 'lodash';
|
import { debounce, get, isNumber, pick, identity } from 'lodash';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { CSSProperties, ReactChild, ReactNode } from 'react';
|
import React, { CSSProperties, ReactChild, ReactNode } from 'react';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
import {
|
import {
|
||||||
AutoSizer,
|
AutoSizer,
|
||||||
CellMeasurer,
|
CellMeasurer,
|
||||||
|
@ -214,6 +215,74 @@ type StateType = {
|
||||||
lastMeasuredWarningHeight: number;
|
lastMeasuredWarningHeight: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getActions = createSelector(
|
||||||
|
// It is expensive to pick so many properties out of the `props` object so we
|
||||||
|
// use `createSelector` to memoize them by the last seen `props` object.
|
||||||
|
identity,
|
||||||
|
|
||||||
|
(props: PropsType): PropsActionsType => {
|
||||||
|
const unsafe = pick(props, [
|
||||||
|
'acknowledgeGroupMemberNameCollisions',
|
||||||
|
'clearChangedMessages',
|
||||||
|
'clearInvitedConversationsForNewlyCreatedGroup',
|
||||||
|
'closeContactSpoofingReview',
|
||||||
|
'setLoadCountdownStart',
|
||||||
|
'setIsNearBottom',
|
||||||
|
'reviewGroupMemberNameCollision',
|
||||||
|
'reviewMessageRequestNameCollision',
|
||||||
|
'learnMoreAboutDeliveryIssue',
|
||||||
|
'loadAndScroll',
|
||||||
|
'loadOlderMessages',
|
||||||
|
'loadNewerMessages',
|
||||||
|
'loadNewestMessages',
|
||||||
|
'markMessageRead',
|
||||||
|
'markViewed',
|
||||||
|
'onBlock',
|
||||||
|
'onBlockAndReportSpam',
|
||||||
|
'onDelete',
|
||||||
|
'onUnblock',
|
||||||
|
'removeMember',
|
||||||
|
'selectMessage',
|
||||||
|
'clearSelectedMessage',
|
||||||
|
'unblurAvatar',
|
||||||
|
'updateSharedGroups',
|
||||||
|
|
||||||
|
'doubleCheckMissingQuoteReference',
|
||||||
|
'onHeightChange',
|
||||||
|
'checkForAccount',
|
||||||
|
'reactToMessage',
|
||||||
|
'replyToMessage',
|
||||||
|
'retrySend',
|
||||||
|
'showForwardMessageModal',
|
||||||
|
'deleteMessage',
|
||||||
|
'deleteMessageForEveryone',
|
||||||
|
'showMessageDetail',
|
||||||
|
'openConversation',
|
||||||
|
'showContactDetail',
|
||||||
|
'showContactModal',
|
||||||
|
'kickOffAttachmentDownload',
|
||||||
|
'markAttachmentAsCorrupted',
|
||||||
|
'showVisualAttachment',
|
||||||
|
'downloadAttachment',
|
||||||
|
'displayTapToViewMessage',
|
||||||
|
'openLink',
|
||||||
|
'scrollToQuotedMessage',
|
||||||
|
'showExpiredIncomingTapToViewToast',
|
||||||
|
'showExpiredOutgoingTapToViewToast',
|
||||||
|
|
||||||
|
'showIdentity',
|
||||||
|
|
||||||
|
'downloadNewVersion',
|
||||||
|
|
||||||
|
'contactSupport',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const safe: AssertProps<PropsActionsType, typeof unsafe> = unsafe;
|
||||||
|
|
||||||
|
return safe;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export class Timeline extends React.PureComponent<PropsType, StateType> {
|
export class Timeline extends React.PureComponent<PropsType, StateType> {
|
||||||
public cellSizeCache = new CellMeasurerCache({
|
public cellSizeCache = new CellMeasurerCache({
|
||||||
defaultHeight: 64,
|
defaultHeight: 64,
|
||||||
|
@ -728,6 +797,8 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
|
||||||
const messageId = items[itemIndex];
|
const messageId = items[itemIndex];
|
||||||
stableKey = messageId;
|
stableKey = messageId;
|
||||||
|
|
||||||
|
const actions = getActions(this.props);
|
||||||
|
|
||||||
rowContents = (
|
rowContents = (
|
||||||
<div
|
<div
|
||||||
id={messageId}
|
id={messageId}
|
||||||
|
@ -737,7 +808,7 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
|
||||||
role="row"
|
role="row"
|
||||||
>
|
>
|
||||||
<ErrorBoundary i18n={i18n} showDebugLog={() => window.showDebugLog()}>
|
<ErrorBoundary i18n={i18n} showDebugLog={() => window.showDebugLog()}>
|
||||||
{renderItem(messageId, id, this.resizeMessage, this.getActions())}
|
{renderItem(messageId, id, this.resizeMessage, actions)}
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1481,66 +1552,4 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
|
||||||
throw missingCaseError(warning);
|
throw missingCaseError(warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getActions(): PropsActionsType {
|
|
||||||
const unsafe = pick(this.props, [
|
|
||||||
'acknowledgeGroupMemberNameCollisions',
|
|
||||||
'clearChangedMessages',
|
|
||||||
'clearInvitedConversationsForNewlyCreatedGroup',
|
|
||||||
'closeContactSpoofingReview',
|
|
||||||
'setLoadCountdownStart',
|
|
||||||
'setIsNearBottom',
|
|
||||||
'reviewGroupMemberNameCollision',
|
|
||||||
'reviewMessageRequestNameCollision',
|
|
||||||
'learnMoreAboutDeliveryIssue',
|
|
||||||
'loadAndScroll',
|
|
||||||
'loadOlderMessages',
|
|
||||||
'loadNewerMessages',
|
|
||||||
'loadNewestMessages',
|
|
||||||
'markMessageRead',
|
|
||||||
'markViewed',
|
|
||||||
'onBlock',
|
|
||||||
'onBlockAndReportSpam',
|
|
||||||
'onDelete',
|
|
||||||
'onUnblock',
|
|
||||||
'removeMember',
|
|
||||||
'selectMessage',
|
|
||||||
'clearSelectedMessage',
|
|
||||||
'unblurAvatar',
|
|
||||||
'updateSharedGroups',
|
|
||||||
|
|
||||||
'doubleCheckMissingQuoteReference',
|
|
||||||
'onHeightChange',
|
|
||||||
'checkForAccount',
|
|
||||||
'reactToMessage',
|
|
||||||
'replyToMessage',
|
|
||||||
'retrySend',
|
|
||||||
'showForwardMessageModal',
|
|
||||||
'deleteMessage',
|
|
||||||
'deleteMessageForEveryone',
|
|
||||||
'showMessageDetail',
|
|
||||||
'openConversation',
|
|
||||||
'showContactDetail',
|
|
||||||
'showContactModal',
|
|
||||||
'kickOffAttachmentDownload',
|
|
||||||
'markAttachmentAsCorrupted',
|
|
||||||
'showVisualAttachment',
|
|
||||||
'downloadAttachment',
|
|
||||||
'displayTapToViewMessage',
|
|
||||||
'openLink',
|
|
||||||
'scrollToQuotedMessage',
|
|
||||||
'showExpiredIncomingTapToViewToast',
|
|
||||||
'showExpiredOutgoingTapToViewToast',
|
|
||||||
|
|
||||||
'showIdentity',
|
|
||||||
|
|
||||||
'downloadNewVersion',
|
|
||||||
|
|
||||||
'contactSupport',
|
|
||||||
]);
|
|
||||||
|
|
||||||
const safe: AssertProps<PropsActionsType, typeof unsafe> = unsafe;
|
|
||||||
|
|
||||||
return safe;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,11 @@ import { StateType as RootStateType } from '../reducer';
|
||||||
import { AttachmentType } from '../../types/Attachment';
|
import { AttachmentType } from '../../types/Attachment';
|
||||||
import { MessageAttributesType } from '../../model-types.d';
|
import { MessageAttributesType } from '../../model-types.d';
|
||||||
import { LinkPreviewWithDomain } from '../../types/LinkPreview';
|
import { LinkPreviewWithDomain } from '../../types/LinkPreview';
|
||||||
|
import { assignWithNoUnnecessaryAllocation } from '../../util/assignWithNoUnnecessaryAllocation';
|
||||||
|
import {
|
||||||
|
REMOVE_PREVIEW as REMOVE_LINK_PREVIEW,
|
||||||
|
RemoveLinkPreviewActionType,
|
||||||
|
} from './linkPreviews';
|
||||||
|
|
||||||
// State
|
// State
|
||||||
|
|
||||||
|
@ -58,6 +63,7 @@ type ComposerActionType =
|
||||||
| ResetComposerActionType
|
| ResetComposerActionType
|
||||||
| SetHighQualitySettingActionType
|
| SetHighQualitySettingActionType
|
||||||
| SetLinkPreviewResultActionType
|
| SetLinkPreviewResultActionType
|
||||||
|
| RemoveLinkPreviewActionType
|
||||||
| SetQuotedMessageActionType;
|
| SetQuotedMessageActionType;
|
||||||
|
|
||||||
// Action Creators
|
// Action Creators
|
||||||
|
@ -176,5 +182,12 @@ export function reducer(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (action.type === REMOVE_LINK_PREVIEW) {
|
||||||
|
return assignWithNoUnnecessaryAllocation(state, {
|
||||||
|
linkPreviewLoading: false,
|
||||||
|
linkPreviewResult: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import { LinkPreviewType } from '../../types/message/LinkPreviews';
|
import { LinkPreviewType } from '../../types/message/LinkPreviews';
|
||||||
|
import { assignWithNoUnnecessaryAllocation } from '../../util/assignWithNoUnnecessaryAllocation';
|
||||||
|
|
||||||
// State
|
// State
|
||||||
|
|
||||||
|
@ -12,14 +13,14 @@ export type LinkPreviewsStateType = {
|
||||||
// Actions
|
// Actions
|
||||||
|
|
||||||
const ADD_PREVIEW = 'linkPreviews/ADD_PREVIEW';
|
const ADD_PREVIEW = 'linkPreviews/ADD_PREVIEW';
|
||||||
const REMOVE_PREVIEW = 'linkPreviews/REMOVE_PREVIEW';
|
export const REMOVE_PREVIEW = 'linkPreviews/REMOVE_PREVIEW';
|
||||||
|
|
||||||
type AddLinkPreviewActionType = {
|
type AddLinkPreviewActionType = {
|
||||||
type: 'linkPreviews/ADD_PREVIEW';
|
type: 'linkPreviews/ADD_PREVIEW';
|
||||||
payload: LinkPreviewType;
|
payload: LinkPreviewType;
|
||||||
};
|
};
|
||||||
|
|
||||||
type RemoveLinkPreviewActionType = {
|
export type RemoveLinkPreviewActionType = {
|
||||||
type: 'linkPreviews/REMOVE_PREVIEW';
|
type: 'linkPreviews/REMOVE_PREVIEW';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -68,9 +69,9 @@ export function reducer(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === REMOVE_PREVIEW) {
|
if (action.type === REMOVE_PREVIEW) {
|
||||||
return {
|
return assignWithNoUnnecessaryAllocation(state, {
|
||||||
linkPreview: undefined,
|
linkPreview: undefined,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
|
|
|
@ -4137,12 +4137,12 @@ Whisper.ConversationView = Whisper.View.extend({
|
||||||
URL.revokeObjectURL(item.url);
|
URL.revokeObjectURL(item.url);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
window.reduxActions.linkPreviews.removeLinkPreview();
|
|
||||||
this.preview = null;
|
this.preview = null;
|
||||||
this.currentlyMatchedLink = null;
|
this.currentlyMatchedLink = null;
|
||||||
this.linkPreviewAbortController?.abort();
|
this.linkPreviewAbortController?.abort();
|
||||||
this.linkPreviewAbortController = null;
|
this.linkPreviewAbortController = null;
|
||||||
this.renderLinkPreview();
|
|
||||||
|
window.reduxActions.linkPreviews.removeLinkPreview();
|
||||||
},
|
},
|
||||||
|
|
||||||
async getStickerPackPreview(
|
async getStickerPackPreview(
|
||||||
|
|
Loading…
Add table
Reference in a new issue