Optimize rendering

This commit is contained in:
Fedor Indutny 2021-08-11 09:23:21 -07:00 committed by GitHub
parent 81f06e2404
commit 12c78c742f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 702 additions and 444 deletions

View file

@ -36,9 +36,6 @@ export const AnnouncementsOnlyGroupBanner = ({
onClick={() => {
openConversation(admin.id);
}}
// Required by the component but unecessary for us
style={{}}
// We don't want these values to show
draftPreview=""
lastMessage={undefined}
lastUpdated={undefined}

View file

@ -54,7 +54,7 @@ const createProps = (rows: ReadonlyArray<Row>): PropsType => ({
onSelectConversation: action('onSelectConversation'),
onClickArchiveButton: action('onClickArchiveButton'),
onClickContactCheckbox: action('onClickContactCheckbox'),
renderMessageSearchResult: (id: string, style: React.CSSProperties) => (
renderMessageSearchResult: (id: string) => (
<MessageSearchResult
body="Lorem ipsum wow"
bodyRanges={[]}
@ -65,7 +65,6 @@ const createProps = (rows: ReadonlyArray<Row>): PropsType => ({
openConversationInternal={action('openConversationInternal')}
sentAt={1587358800000}
snippet="Lorem <<left>>ipsum<<right>> wow"
style={style}
to={defaultConversations[1]}
/>
),
@ -288,6 +287,7 @@ story.add('Contact checkboxes: disabled', () => (
story.add('Conversation: Typing Status', () =>
renderConversation({
typingContact: {
...getDefaultConversation(),
name: 'Someone Here',
},
})

View file

@ -1,9 +1,10 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { useRef, useEffect, useCallback, CSSProperties } from 'react';
import React, { useRef, useEffect, useCallback, ReactNode } from 'react';
import { List, ListRowRenderer } from 'react-virtualized';
import classNames from 'classnames';
import { pick } from 'lodash';
import { missingCaseError } from '../util/missingCaseError';
import { assert } from '../util/assert';
@ -128,7 +129,7 @@ export type PropsType = {
disabledReason: undefined | ContactCheckboxDisabledReason
) => void;
onSelectConversation: (conversationId: string, messageId?: string) => void;
renderMessageSearchResult: (id: string, style: CSSProperties) => JSX.Element;
renderMessageSearchResult: (id: string) => JSX.Element;
showChooseGroupMembers: () => void;
startNewConversationFromPhoneNumber: (e164: string) => void;
};
@ -187,13 +188,12 @@ export const ConversationList: React.FC<PropsType> = ({
return <div key={key} style={style} />;
}
let result: ReactNode;
switch (row.type) {
case RowType.ArchiveButton:
return (
result = (
<button
key={key}
className="module-conversation-list__item--archive-button"
style={style}
onClick={onClickArchiveButton}
type="button"
>
@ -203,90 +203,108 @@ export const ConversationList: React.FC<PropsType> = ({
</span>
</button>
);
break;
case RowType.Blank:
return <div key={key} style={style} />;
result = <></>;
break;
case RowType.Contact: {
const { isClickable = true } = row;
return (
result = (
<ContactListItem
{...row.contact}
key={key}
style={style}
onClick={isClickable ? onSelectConversation : undefined}
i18n={i18n}
/>
);
break;
}
case RowType.ContactCheckbox:
return (
result = (
<ContactCheckboxComponent
{...row.contact}
isChecked={row.isChecked}
disabledReason={row.disabledReason}
key={key}
style={style}
onClick={onClickContactCheckbox}
i18n={i18n}
/>
);
case RowType.Conversation:
return (
break;
case RowType.Conversation: {
const itemProps = pick(row.conversation, [
'acceptedMessageRequest',
'avatarPath',
'color',
'draftPreview',
'id',
'isMe',
'isSelected',
'lastMessage',
'lastUpdated',
'markedUnread',
'muteExpiresAt',
'name',
'phoneNumber',
'profileName',
'sharedGroupNames',
'shouldShowDraft',
'title',
'type',
'typingContact',
'unblurredAvatarPath',
'unreadCount',
]);
result = (
<ConversationListItem
{...row.conversation}
{...itemProps}
key={key}
style={style}
onClick={onSelectConversation}
i18n={i18n}
/>
);
break;
}
case RowType.CreateNewGroup:
return (
result = (
<CreateNewGroupButton
i18n={i18n}
key={key}
onClick={showChooseGroupMembers}
style={style}
/>
);
break;
case RowType.Header:
return (
<div
className="module-conversation-list__item--header"
key={key}
style={style}
>
result = (
<div className="module-conversation-list__item--header">
{i18n(row.i18nKey)}
</div>
);
break;
case RowType.MessageSearchResult:
return (
<React.Fragment key={key}>
{renderMessageSearchResult(row.messageId, style)}
</React.Fragment>
);
result = <>{renderMessageSearchResult(row.messageId)}</>;
break;
case RowType.SearchResultsLoadingFakeHeader:
return (
<SearchResultsLoadingFakeHeaderComponent key={key} style={style} />
);
result = <SearchResultsLoadingFakeHeaderComponent />;
break;
case RowType.SearchResultsLoadingFakeRow:
return (
<SearchResultsLoadingFakeRowComponent key={key} style={style} />
);
result = <SearchResultsLoadingFakeRowComponent />;
break;
case RowType.StartNewConversation:
return (
result = (
<StartNewConversationComponent
i18n={i18n}
key={key}
phoneNumber={row.phoneNumber}
onClick={() => {
startNewConversationFromPhoneNumber(row.phoneNumber);
}}
style={style}
onClick={startNewConversationFromPhoneNumber}
/>
);
break;
default:
throw missingCaseError(row);
}
return (
<span style={style} key={key}>
{result}
</span>
);
},
[
getRow,

View file

@ -98,7 +98,7 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
setChallengeStatus: action('setChallengeStatus'),
renderExpiredBuildDialog: () => <div />,
renderMainHeader: () => <div />,
renderMessageSearchResult: (id: string, style: React.CSSProperties) => (
renderMessageSearchResult: (id: string) => (
<MessageSearchResult
body="Lorem ipsum wow"
bodyRanges={[]}
@ -109,7 +109,6 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
openConversationInternal={action('openConversationInternal')}
sentAt={1587358800000}
snippet="Lorem <<left>>ipsum<<right>> wow"
style={style}
to={defaultConversations[1]}
/>
),

View file

@ -1,7 +1,7 @@
// Copyright 2019-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { useEffect, useMemo, CSSProperties } from 'react';
import React, { useEffect, useCallback, useMemo } from 'react';
import Measure, { MeasuredComponentProps } from 'react-measure';
import { isNumber } from 'lodash';
@ -119,7 +119,7 @@ export type PropsType = {
// Render Props
renderExpiredBuildDialog: () => JSX.Element;
renderMainHeader: () => JSX.Element;
renderMessageSearchResult: (id: string, style: CSSProperties) => JSX.Element;
renderMessageSearchResult: (id: string) => JSX.Element;
renderNetworkStatus: () => JSX.Element;
renderRelinkDialog: () => JSX.Element;
renderUpdateDialog: () => JSX.Element;
@ -376,6 +376,17 @@ export const LeftPane: React.FC<PropsType> = ({
const getRow = useMemo(() => helper.getRow.bind(helper), [helper]);
const onSelectConversation = useCallback(
(conversationId: string, messageId?: string) => {
openConversationInternal({
conversationId,
messageId,
switchToAssociatedView: true,
});
},
[openConversationInternal]
);
const previousSelectedConversationId = usePrevious(
selectedConversationId,
selectedConversationId
@ -458,16 +469,7 @@ export const LeftPane: React.FC<PropsType> = ({
throw missingCaseError(disabledReason);
}
}}
onSelectConversation={(
conversationId: string,
messageId?: string
) => {
openConversationInternal({
conversationId,
messageId,
switchToAssociatedView: true,
});
}}
onSelectConversation={onSelectConversation}
renderMessageSearchResult={renderMessageSearchResult}
rowCount={helper.getRowCount()}
scrollBehavior={scrollBehavior}

View file

@ -271,7 +271,7 @@ type State = {
const EXPIRATION_CHECK_MINIMUM = 2000;
const EXPIRED_DELAY = 600;
export class Message extends React.Component<Props, State> {
export class Message extends React.PureComponent<Props, State> {
public menuTriggerRef: Trigger | undefined;
public focusRef: React.RefObject<HTMLDivElement> = React.createRef();

View file

@ -375,7 +375,6 @@ const renderItem = (id: string) => (
i18n={i18n}
interactionMode="keyboard"
conversationId=""
conversationAccepted
renderContact={() => '*ContactName*'}
renderUniversalTimerNotification={() => (
<div>*UniversalTimerNotification*</div>

View file

@ -1,7 +1,7 @@
// Copyright 2019-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { debounce, get, isNumber } from 'lodash';
import { debounce, get, isNumber, pick } from 'lodash';
import classNames from 'classnames';
import React, { CSSProperties, ReactChild, ReactNode } from 'react';
import {
@ -15,12 +15,14 @@ import Measure from 'react-measure';
import { ScrollDownButton } from './ScrollDownButton';
import { LocalizerType } from '../../types/Util';
import { AssertProps, LocalizerType } from '../../types/Util';
import { ConversationType } from '../../state/ducks/conversations';
import { assert } from '../../util/assert';
import { missingCaseError } from '../../util/missingCaseError';
import { PropsActions as MessageActionsType } from './Message';
import { PropsActions as UnsupportedMessageActionsType } from './UnsupportedMessage';
import { PropsActionsType as ChatSessionRefreshedNotificationActionsType } from './ChatSessionRefreshedNotification';
import { ErrorBoundary } from './ErrorBoundary';
import { PropsActions as SafetyNumberActionsType } from './SafetyNumberNotification';
import { Intl } from '../Intl';
@ -104,7 +106,7 @@ type PropsHousekeepingType = {
id: string,
conversationId: string,
onHeightChange: (messageId: string) => unknown,
actions: Record<string, unknown>
actions: PropsActionsType
) => JSX.Element;
renderLastSeenIndicator: (id: string) => JSX.Element;
renderHeroRow: (
@ -117,7 +119,7 @@ type PropsHousekeepingType = {
renderTypingBubble: (id: string) => JSX.Element;
};
type PropsActionsType = {
export type PropsActionsType = {
acknowledgeGroupMemberNameCollisions: (
groupNameCollisions: Readonly<GroupNameCollisionsWithIdsByTitle>
) => void;
@ -152,7 +154,9 @@ type PropsActionsType = {
unblurAvatar: () => void;
updateSharedGroups: () => unknown;
} & MessageActionsType &
SafetyNumberActionsType;
SafetyNumberActionsType &
UnsupportedMessageActionsType &
ChatSessionRefreshedNotificationActionsType;
export type PropsType = PropsDataType &
PropsHousekeepingType &
@ -721,6 +725,7 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
);
}
const messageId = items[itemIndex];
rowContents = (
<div
id={messageId}
@ -730,7 +735,7 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
role="row"
>
<ErrorBoundary i18n={i18n} showDebugLog={() => window.showDebugLog()}>
{renderItem(messageId, id, this.resizeMessage, this.props)}
{renderItem(messageId, id, this.resizeMessage, this.getActions())}
</ErrorBoundary>
</div>
);
@ -1474,4 +1479,65 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
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',
'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;
}
}

View file

@ -42,7 +42,6 @@ const renderUniversalTimerNotification = () => (
const getDefaultProps = () => ({
conversationId: 'conversation-id',
conversationAccepted: true,
id: 'asdf',
isSelected: false,
interactionMode: 'keyboard' as const,

View file

@ -2,6 +2,8 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import { omit } from 'lodash';
import { LocalizerType, ThemeType } from '../../types/Util';
import { InteractionModeType } from '../../state/ducks/conversations';
@ -152,7 +154,6 @@ export type TimelineItemType =
type PropsLocalType = {
conversationId: string;
conversationAccepted: boolean;
item?: TimelineItemType;
id: string;
isSelected: boolean;
@ -201,7 +202,7 @@ export class TimelineItem extends React.PureComponent<PropsType> {
if (item.type === 'message') {
return (
<Message
{...this.props}
{...omit(this.props, ['item'])}
{...item.data}
i18n={i18n}
theme={theme}

View file

@ -1,7 +1,7 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { ReactNode, CSSProperties, FunctionComponent } from 'react';
import React, { ReactNode, FunctionComponent } from 'react';
import classNames from 'classnames';
import { isBoolean, isNumber } from 'lodash';
@ -37,7 +37,6 @@ type PropsType = {
messageStatusIcon?: ReactNode;
messageText?: ReactNode;
onClick?: () => void;
style: CSSProperties;
unreadCount?: number;
} & Pick<
ConversationType,
@ -77,7 +76,6 @@ export const BaseConversationListItem: FunctionComponent<PropsType> = React.memo
phoneNumber,
profileName,
sharedGroupNames,
style,
title,
unblurredAvatarPath,
unreadCount,
@ -198,7 +196,6 @@ export const BaseConversationListItem: FunctionComponent<PropsType> = React.memo
{ [`${BASE_CLASS_NAME}--is-checkbox--disabled`]: disabled }
)}
data-id={id ? cleanId(id) : undefined}
style={style}
// `onClick` is will double-fire if we're enabled. We want it to fire when we're
// disabled so we can show any "can't add contact" modals, etc. This won't
// work for keyboard users, though, because labels are not tabbable.
@ -219,7 +216,6 @@ export const BaseConversationListItem: FunctionComponent<PropsType> = React.memo
data-id={id ? cleanId(id) : undefined}
disabled={disabled}
onClick={onClick}
style={style}
type="button"
>
{contents}
@ -228,11 +224,7 @@ export const BaseConversationListItem: FunctionComponent<PropsType> = React.memo
}
return (
<div
className={commonClassNames}
data-id={id ? cleanId(id) : undefined}
style={style}
>
<div className={commonClassNames} data-id={id ? cleanId(id) : undefined}>
{contents}
</div>
);

View file

@ -1,7 +1,7 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { CSSProperties, FunctionComponent, ReactNode } from 'react';
import React, { FunctionComponent, ReactNode } from 'react';
import { BaseConversationListItem } from './BaseConversationListItem';
import { ConversationType } from '../../state/ducks/conversations';
@ -38,7 +38,6 @@ export type PropsDataType = {
type PropsHousekeepingType = {
i18n: LocalizerType;
style: CSSProperties;
onClick: (
id: string,
disabledReason: undefined | ContactCheckboxDisabledReason
@ -63,7 +62,6 @@ export const ContactCheckbox: FunctionComponent<PropsType> = React.memo(
phoneNumber,
profileName,
sharedGroupNames,
style,
title,
type,
unblurredAvatarPath,
@ -114,7 +112,6 @@ export const ContactCheckbox: FunctionComponent<PropsType> = React.memo(
phoneNumber={phoneNumber}
profileName={profileName}
sharedGroupNames={sharedGroupNames}
style={style}
title={title}
unblurredAvatarPath={unblurredAvatarPath}
/>

View file

@ -1,7 +1,7 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { CSSProperties, FunctionComponent } from 'react';
import React, { FunctionComponent } from 'react';
import { BaseConversationListItem } from './BaseConversationListItem';
import { ConversationType } from '../../state/ducks/conversations';
@ -28,7 +28,6 @@ export type PropsDataType = Pick<
type PropsHousekeepingType = {
i18n: LocalizerType;
style: CSSProperties;
onClick?: (id: string) => void;
};
@ -48,7 +47,6 @@ export const ContactListItem: FunctionComponent<PropsType> = React.memo(
phoneNumber,
profileName,
sharedGroupNames,
style,
title,
type,
unblurredAvatarPath,
@ -85,7 +83,6 @@ export const ContactListItem: FunctionComponent<PropsType> = React.memo(
phoneNumber={phoneNumber}
profileName={profileName}
sharedGroupNames={sharedGroupNames}
style={style}
title={title}
unblurredAvatarPath={unblurredAvatarPath}
/>

View file

@ -1,12 +1,7 @@
// Copyright 2018-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, {
useCallback,
CSSProperties,
FunctionComponent,
ReactNode,
} from 'react';
import React, { useCallback, FunctionComponent, ReactNode } from 'react';
import classNames from 'classnames';
import {
@ -62,7 +57,6 @@ export type PropsData = Pick<
type PropsHousekeeping = {
i18n: LocalizerType;
style: CSSProperties;
onClick: (id: string) => void;
};
@ -88,7 +82,6 @@ export const ConversationListItem: FunctionComponent<Props> = React.memo(
profileName,
sharedGroupNames,
shouldShowDraft,
style,
title,
type,
typingContact,
@ -197,7 +190,6 @@ export const ConversationListItem: FunctionComponent<Props> = React.memo(
phoneNumber={phoneNumber}
profileName={profileName}
sharedGroupNames={sharedGroupNames}
style={style}
title={title}
unreadCount={unreadCount}
unblurredAvatarPath={unblurredAvatarPath}

View file

@ -1,7 +1,7 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { CSSProperties, FunctionComponent } from 'react';
import React, { FunctionComponent } from 'react';
import { BaseConversationListItem } from './BaseConversationListItem';
import { LocalizerType } from '../../types/Util';
@ -9,11 +9,10 @@ import { LocalizerType } from '../../types/Util';
type PropsType = {
i18n: LocalizerType;
onClick: () => void;
style: CSSProperties;
};
export const CreateNewGroupButton: FunctionComponent<PropsType> = React.memo(
({ i18n, onClick, style }) => {
({ i18n, onClick }) => {
const title = i18n('createNewGroupButton');
return (
@ -26,7 +25,6 @@ export const CreateNewGroupButton: FunctionComponent<PropsType> = React.memo(
isSelected={false}
onClick={onClick}
sharedGroupNames={[]}
style={style}
title={title}
/>
);

View file

@ -55,7 +55,6 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
'isSearchingInConversation',
overrideProps.isSearchingInConversation || false
),
style: {},
});
story.add('Default', () => {

View file

@ -1,12 +1,7 @@
// Copyright 2019-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, {
useCallback,
CSSProperties,
FunctionComponent,
ReactNode,
} from 'react';
import React, { useCallback, FunctionComponent, ReactNode } from 'react';
import { escapeRegExp } from 'lodash';
import { MessageBodyHighlight } from './MessageBodyHighlight';
@ -59,7 +54,6 @@ type PropsHousekeepingType = {
conversationId: string;
messageId?: string;
}) => void;
style: CSSProperties;
};
export type PropsType = PropsDataType & PropsHousekeepingType;
@ -159,7 +153,6 @@ export const MessageSearchResult: FunctionComponent<PropsType> = React.memo(
openConversationInternal,
sentAt,
snippet,
style,
to,
}) => {
const onClickItem = useCallback(() => {
@ -167,7 +160,7 @@ export const MessageSearchResult: FunctionComponent<PropsType> = React.memo(
}, [openConversationInternal, conversationId, id]);
if (!from || !to) {
return <div style={style} />;
return <div />;
}
const isNoteToSelf = from.isMe && to.isMe;
@ -213,7 +206,6 @@ export const MessageSearchResult: FunctionComponent<PropsType> = React.memo(
phoneNumber={from.phoneNumber}
profileName={from.profileName}
sharedGroupNames={from.sharedGroupNames}
style={style}
title={from.title}
unblurredAvatarPath={from.unblurredAvatarPath}
/>

View file

@ -1,12 +1,10 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { CSSProperties, FunctionComponent } from 'react';
import React, { FunctionComponent } from 'react';
type PropsType = {
style: CSSProperties;
};
type PropsType = Record<string, never>;
export const SearchResultsLoadingFakeHeader: FunctionComponent<PropsType> = ({
style,
}) => <div className="module-SearchResultsLoadingFakeHeader" style={style} />;
export const SearchResultsLoadingFakeHeader: FunctionComponent<PropsType> = () => (
<div className="module-SearchResultsLoadingFakeHeader" />
);

View file

@ -1,16 +1,12 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { CSSProperties, FunctionComponent } from 'react';
import React, { FunctionComponent } from 'react';
type PropsType = {
style: CSSProperties;
};
type PropsType = Record<string, never>;
export const SearchResultsLoadingFakeRow: FunctionComponent<PropsType> = ({
style,
}) => (
<div className="module-SearchResultsLoadingFakeRow" style={style}>
export const SearchResultsLoadingFakeRow: FunctionComponent<PropsType> = () => (
<div className="module-SearchResultsLoadingFakeRow">
<div className="module-SearchResultsLoadingFakeRow__avatar" />
<div className="module-SearchResultsLoadingFakeRow__content">
<div className="module-SearchResultsLoadingFakeRow__content__header" />

View file

@ -1,7 +1,7 @@
// Copyright 2019-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { CSSProperties, FunctionComponent } from 'react';
import React, { FunctionComponent, useCallback } from 'react';
import {
BaseConversationListItem,
@ -19,18 +19,21 @@ type PropsData = {
type PropsHousekeeping = {
i18n: LocalizerType;
style: CSSProperties;
onClick: () => void;
onClick: (phoneNumber: string) => void;
};
export type Props = PropsData & PropsHousekeeping;
export const StartNewConversation: FunctionComponent<Props> = React.memo(
({ i18n, onClick, phoneNumber, style }) => {
({ i18n, onClick, phoneNumber }) => {
const messageText = (
<div className={TEXT_CLASS_NAME}>{i18n('startConversation')}</div>
);
const boundOnClick = useCallback(() => {
onClick(phoneNumber);
}, [onClick, phoneNumber]);
return (
<BaseConversationListItem
acceptedMessageRequest={false}
@ -41,10 +44,9 @@ export const StartNewConversation: FunctionComponent<Props> = React.memo(
isMe={false}
isSelected={false}
messageText={messageText}
onClick={onClick}
onClick={boundOnClick}
phoneNumber={phoneNumber}
sharedGroupNames={[]}
style={style}
title={phoneNumber}
/>
);