Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ReportScreen rendering optimisation #29815

3 changes: 2 additions & 1 deletion src/components/OnyxProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import ComposeProviders from './ComposeProviders';
// Set up any providers for individual keys. This should only be used in cases where many components will subscribe to
// the same key (e.g. FlatList renderItem components)
const [withNetwork, NetworkProvider, NetworkContext] = createOnyxContext(ONYXKEYS.NETWORK, {});
const [withPersonalDetails, PersonalDetailsProvider] = createOnyxContext(ONYXKEYS.PERSONAL_DETAILS_LIST);
const [withPersonalDetails, PersonalDetailsProvider, , usePersonalDetails] = createOnyxContext(ONYXKEYS.PERSONAL_DETAILS_LIST);
const [withCurrentDate, CurrentDateProvider] = createOnyxContext(ONYXKEYS.CURRENT_DATE);
const [withReportActionsDrafts, ReportActionsDraftsProvider] = createOnyxContext(ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS);
const [withBlockedFromConcierge, BlockedFromConciergeProvider] = createOnyxContext(ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE);
Expand Down Expand Up @@ -47,6 +47,7 @@ export default OnyxProvider;
export {
withNetwork,
withPersonalDetails,
usePersonalDetails,
withReportActionsDrafts,
withCurrentDate,
withBlockedFromConcierge,
Expand Down
12 changes: 10 additions & 2 deletions src/components/createOnyxContext.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {createContext, forwardRef} from 'react';
import React, {createContext, forwardRef, useContext} from 'react';
import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import Str from 'expensify-common/lib/str';
Expand Down Expand Up @@ -54,5 +54,13 @@ export default (onyxKeyName, defaultValue) => {
return Consumer;
};

return [withOnyxKey, ProviderWithOnyx, Context];
const useOnyxContext = () => {
const context = useContext(Context);
if (context === null) {
throw new Error(`useOnyxContext must be used within a OnyxProvider [key: ${onyxKeyName}]`);
}
return context;
};

return [withOnyxKey, ProviderWithOnyx, Context, useOnyxContext];
};
7 changes: 3 additions & 4 deletions src/components/withCurrentUserPersonalDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import getComponentDisplayName from '../libs/getComponentDisplayName';
import ONYXKEYS from '../ONYXKEYS';
import personalDetailsPropType from '../pages/personalDetailsPropType';
import refPropTypes from './refPropTypes';
import {usePersonalDetails} from './OnyxProvider';

const withCurrentUserPersonalDetailsPropTypes = {
currentUserPersonalDetails: personalDetailsPropType,
Expand Down Expand Up @@ -35,8 +36,9 @@ export default function (WrappedComponent) {
};

function WithCurrentUserPersonalDetails(props) {
const personalDetails = usePersonalDetails();
const accountID = props.session.accountID;
const accountPersonalDetails = props.personalDetails[accountID];
const accountPersonalDetails = personalDetails[accountID];
const currentUserPersonalDetails = useMemo(() => ({...accountPersonalDetails, accountID}), [accountPersonalDetails, accountID]);
return (
<WrappedComponent
Expand All @@ -62,9 +64,6 @@ export default function (WrappedComponent) {
));

return withOnyx({
personalDetails: {
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
},
session: {
key: ONYXKEYS.SESSION,
},
Expand Down
2 changes: 1 addition & 1 deletion src/pages/home/ReportScreen.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useRef, useState, useEffect, useMemo, useCallback} from 'react';
import React, {useRef, useState, useEffect, useMemo, useCallback, createContext} from 'react';
import {withOnyx} from 'react-native-onyx';
import {useFocusEffect} from '@react-navigation/native';
import PropTypes from 'prop-types';
Expand Down
13 changes: 6 additions & 7 deletions src/pages/home/report/ReportActionItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import MiniReportActionContextMenu from './ContextMenu/MiniReportActionContextMe
import * as ReportActionContextMenu from './ContextMenu/ReportActionContextMenu';
import * as ContextMenuActions from './ContextMenu/ContextMenuActions';
import * as EmojiPickerAction from '../../../libs/actions/EmojiPickerAction';
import {withBlockedFromConcierge, withNetwork, withPersonalDetails, withReportActionsDrafts} from '../../../components/OnyxProvider';
import {usePersonalDetails, withBlockedFromConcierge, withNetwork, withPersonalDetails, withReportActionsDrafts} from '../../../components/OnyxProvider';
import RenameAction from '../../../components/ReportActionItem/RenameAction';
import InlineSystemMessage from '../../../components/InlineSystemMessage';
import styles from '../../../styles/styles';
Expand Down Expand Up @@ -70,6 +70,7 @@ import themeColors from '../../../styles/themes/default';
import ReportActionItemBasicMessage from './ReportActionItemBasicMessage';
import RenderHTML from '../../../components/RenderHTML';
import ReportAttachmentsContext from './ReportAttachmentsContext';
import {PersonalDetailsContext} from '../ReportScreen';

const propTypes = {
...windowDimensionsPropTypes,
Expand Down Expand Up @@ -107,7 +108,6 @@ const propTypes = {

...windowDimensionsPropTypes,
emojiReactions: EmojiReactionsPropTypes,
personalDetailsList: PropTypes.objectOf(personalDetailsPropType),

/** IOU report for this action, if any */
iouReport: reportPropTypes,
Expand All @@ -120,14 +120,14 @@ const defaultProps = {
draftMessage: '',
preferredSkinTone: CONST.EMOJI_DEFAULT_SKIN_TONE,
emojiReactions: {},
personalDetailsList: {},
shouldShowSubscriptAvatar: false,
hasOutstandingIOU: false,
iouReport: undefined,
shouldHideThreadDividerLine: false,
};

function ReportActionItem(props) {
const personalDetails = usePersonalDetails();
const [isContextMenuActive, setIsContextMenuActive] = useState(ReportActionContextMenu.isActiveReportAction(props.action.reportActionID));
const [isHidden, setIsHidden] = useState(false);
const [moderationDecision, setModerationDecision] = useState(CONST.MODERATION.MODERATOR_DECISION_APPROVED);
Expand Down Expand Up @@ -344,7 +344,7 @@ function ReportActionItem(props) {
/>
);
} else if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTQUEUED) {
const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetailsList, [props.report.ownerAccountID, 'displayName'], props.report.ownerEmail);
const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(personalDetails, [props.report.ownerAccountID, 'displayName'], props.report.ownerEmail);
const shouldShowAddCreditBankAccountButton =
ReportUtils.isCurrentUserSubmitter(props.report.reportID) && !store.hasCreditBankAccount() && !ReportUtils.isSettled(props.report.reportID);

Expand Down Expand Up @@ -467,7 +467,7 @@ function ReportActionItem(props) {
numberOfReplies={numberOfThreadReplies}
mostRecentReply={`${props.action.childLastVisibleActionCreated}`}
isHovered={hovered}
icons={ReportUtils.getIconsForParticipants(oldestFourAccountIDs, props.personalDetailsList)}
icons={ReportUtils.getIconsForParticipants(oldestFourAccountIDs, personalDetails)}
onSecondaryInteraction={showPopover}
/>
</View>
Expand Down Expand Up @@ -594,7 +594,7 @@ function ReportActionItem(props) {
const isWhisper = whisperedToAccountIDs.length > 0;
const isMultipleParticipant = whisperedToAccountIDs.length > 1;
const isWhisperOnlyVisibleByUser = isWhisper && ReportUtils.isCurrentUserTheOnlyParticipant(whisperedToAccountIDs);
const whisperedToPersonalDetails = isWhisper ? _.filter(props.personalDetailsList, (details) => _.includes(whisperedToAccountIDs, details.accountID)) : [];
const whisperedToPersonalDetails = isWhisper ? _.filter(personalDetails, (details) => _.includes(whisperedToAccountIDs, details.accountID)) : [];
const displayNamesWithTooltips = isWhisper ? ReportUtils.getDisplayNamesWithTooltips(whisperedToPersonalDetails, isMultipleParticipant) : [];
return (
<PressableWithSecondaryInteraction
Expand Down Expand Up @@ -676,7 +676,6 @@ export default compose(
withWindowDimensions,
withLocalize,
withNetwork(),
withPersonalDetails(),
withBlockedFromConcierge({propName: 'blockedFromConcierge'}),
withReportActionsDrafts({
propName: 'draftMessage',
Expand Down
19 changes: 7 additions & 12 deletions src/pages/home/report/ReportActionItemSingle.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ import ReportActionItemFragment from './ReportActionItemFragment';
import styles from '../../../styles/styles';
import ReportActionItemDate from './ReportActionItemDate';
import Avatar from '../../../components/Avatar';
import personalDetailsPropType from '../../personalDetailsPropType';
import compose from '../../../libs/compose';
import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
import Navigation from '../../../libs/Navigation/Navigation';
import ROUTES from '../../../ROUTES';
import {withPersonalDetails} from '../../../components/OnyxProvider';
import {usePersonalDetails} from '../../../components/OnyxProvider';
import ControlSelection from '../../../libs/ControlSelection';
import * as ReportUtils from '../../../libs/ReportUtils';
import OfflineWithFeedback from '../../../components/OfflineWithFeedback';
Expand All @@ -37,9 +36,6 @@ const propTypes = {
/** All the data of the action */
action: PropTypes.shape(reportActionPropTypes).isRequired,

/** All of the personalDetails */
personalDetailsList: PropTypes.objectOf(personalDetailsPropType),

/** Styles for the outermost View */
// eslint-disable-next-line react/forbid-prop-types
wrapperStyles: PropTypes.arrayOf(PropTypes.object),
Expand Down Expand Up @@ -69,7 +65,6 @@ const propTypes = {
};

const defaultProps = {
personalDetailsList: {},
wrapperStyles: [styles.chatItem],
showHeader: true,
shouldShowSubscriptAvatar: false,
Expand All @@ -88,9 +83,10 @@ const showWorkspaceDetails = (reportID) => {
};

function ReportActionItemSingle(props) {
const personalDetails = usePersonalDetails();
const actorAccountID = props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && props.iouReport ? props.iouReport.managerID : props.action.actorAccountID;
let {displayName} = props.personalDetailsList[actorAccountID] || {};
const {avatar, login, pendingFields, status, fallbackIcon} = props.personalDetailsList[actorAccountID] || {};
let {displayName} = personalDetails[actorAccountID] || {};
const {avatar, login, pendingFields, status, fallbackIcon} = personalDetails[actorAccountID] || {};
let actorHint = (login || displayName || '').replace(CONST.REGEX.MERGED_ACCOUNT_PREFIX, '');
const displayAllActors = useMemo(() => props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && props.iouReport, [props.action.actionName, props.iouReport]);
const isWorkspaceActor = ReportUtils.isPolicyExpenseChat(props.report) && (!actorAccountID || displayAllActors);
Expand All @@ -100,10 +96,10 @@ function ReportActionItemSingle(props) {
displayName = ReportUtils.getPolicyName(props.report);
actorHint = displayName;
avatarSource = ReportUtils.getWorkspaceAvatar(props.report);
} else if (props.action.delegateAccountID && props.personalDetailsList[props.action.delegateAccountID]) {
} else if (props.action.delegateAccountID && personalDetails[props.action.delegateAccountID]) {
// We replace the actor's email, name, and avatar with the Copilot manually for now. And only if we have their
// details. This will be improved upon when the Copilot feature is implemented.
const delegateDetails = props.personalDetailsList[props.action.delegateAccountID];
const delegateDetails = personalDetails[props.action.delegateAccountID];
const delegateDisplayName = delegateDetails.displayName;
actorHint = `${delegateDisplayName} (${props.translate('reportAction.asCopilot')} ${displayName})`;
displayName = actorHint;
Expand All @@ -116,7 +112,7 @@ function ReportActionItemSingle(props) {
if (displayAllActors) {
// The ownerAccountID and actorAccountID can be the same if the a user requests money back from the IOU's original creator, in that case we need to use managerID to avoid displaying the same user twice
const secondaryAccountId = props.iouReport.ownerAccountID === actorAccountID ? props.iouReport.managerID : props.iouReport.ownerAccountID;
const secondaryUserDetails = props.personalDetailsList[secondaryAccountId] || {};
const secondaryUserDetails = personalDetails[secondaryAccountId] || {};
const secondaryDisplayName = lodashGet(secondaryUserDetails, 'displayName', '');
displayName = `${primaryDisplayName} & ${secondaryDisplayName}`;
secondaryAvatar = {
Expand Down Expand Up @@ -270,7 +266,6 @@ ReportActionItemSingle.displayName = 'ReportActionItemSingle';

export default compose(
withLocalize,
withPersonalDetails(),
withOnyx({
betas: {
key: ONYXKEYS.BETAS,
Expand Down
Loading