Skip to content

Commit 3be5e69

Browse files
committed
Separate ReportScreenContext to prevent cyclic re-renders
1 parent fd407e2 commit 3be5e69

File tree

7 files changed

+110
-110
lines changed

7 files changed

+110
-110
lines changed

src/components/Reactions/ReportActionItemEmojiReactions.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import EmojiReactionsPropTypes from './EmojiReactionsPropTypes';
1313
import Tooltip from '../Tooltip';
1414
import ReactionTooltipContent from './ReactionTooltipContent';
1515
import * as EmojiUtils from '../../libs/EmojiUtils';
16-
import ReportScreenContext from '../../pages/home/ReportScreenContext';
16+
import {ReactionListContext} from '../../pages/home/ReportScreenContext';
1717

1818
const propTypes = {
1919
emojiReactions: EmojiReactionsPropTypes,
@@ -41,7 +41,7 @@ const defaultProps = {
4141
};
4242

4343
function ReportActionItemEmojiReactions(props) {
44-
const {reactionListRef} = useContext(ReportScreenContext);
44+
const reactionListRef = useContext(ReactionListContext);
4545
const popoverReactionListAnchor = useRef(null);
4646
let totalReactionCount = 0;
4747

src/hooks/useReportScrollManager/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import {useContext, useCallback} from 'react';
2-
import ReportScreenContext from '../../pages/home/ReportScreenContext';
2+
import {ActionListContext} from '../../pages/home/ReportScreenContext';
33

44
function useReportScrollManager() {
5-
const {flatListRef} = useContext(ReportScreenContext);
5+
const flatListRef = useContext(ActionListContext);
66

77
/**
88
* Scroll to the provided index. On non-native implementations we do not want to scroll when we are scrolling because

src/hooks/useReportScrollManager/index.native.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import {useContext, useCallback} from 'react';
2-
import ReportScreenContext from '../../pages/home/ReportScreenContext';
2+
import {ActionListContext} from '../../pages/home/ReportScreenContext';
33

44
function useReportScrollManager() {
5-
const {flatListRef} = useContext(ReportScreenContext);
5+
const flatListRef = useContext(ActionListContext);
66

77
/**
88
* Scroll to the provided index.

src/pages/home/ReportScreen.js

Lines changed: 92 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import getIsReportFullyVisible from '../../libs/getIsReportFullyVisible';
3333
import MoneyRequestHeader from '../../components/MoneyRequestHeader';
3434
import MoneyReportHeader from '../../components/MoneyReportHeader';
3535
import * as ComposerActions from '../../libs/actions/Composer';
36-
import ReportScreenContext from './ReportScreenContext';
36+
import {ActionListContext, ReactionListContext} from './ReportScreenContext';
3737
import TaskHeaderActionButton from '../../components/TaskHeaderActionButton';
3838
import DragAndDropProvider from '../../components/DragAndDrop/Provider';
3939

@@ -276,111 +276,107 @@ class ReportScreen extends React.Component {
276276
}
277277

278278
return (
279-
<ReportScreenContext.Provider
280-
value={{
281-
flatListRef: this.flatListRef,
282-
reactionListRef: this.reactionListRef,
283-
}}
284-
>
285-
<ScreenWrapper
286-
style={screenWrapperStyle}
287-
shouldEnableKeyboardAvoidingView={isTopMostReportId}
288-
>
289-
<FullPageNotFoundView
290-
shouldShow={(!this.props.report.reportID && !this.props.report.isLoadingReportActions && !isLoading) || shouldHideReport}
291-
subtitleKey="notFound.noAccess"
292-
shouldShowCloseButton={false}
293-
shouldShowBackButton={this.props.isSmallScreenWidth}
294-
onBackButtonPress={Navigation.goBack}
295-
shouldShowLink={false}
279+
<ActionListContext.Provider value={this.flatListRef}>
280+
<ReactionListContext.Provider value={this.reactionListRef}>
281+
<ScreenWrapper
282+
style={screenWrapperStyle}
283+
shouldEnableKeyboardAvoidingView={isTopMostReportId}
296284
>
297-
<OfflineWithFeedback
298-
pendingAction={addWorkspaceRoomOrChatPendingAction}
299-
errors={addWorkspaceRoomOrChatErrors}
300-
shouldShowErrorMessages={false}
301-
needsOffscreenAlphaCompositing
285+
<FullPageNotFoundView
286+
shouldShow={(!this.props.report.reportID && !this.props.report.isLoadingReportActions && !isLoading) || shouldHideReport}
287+
subtitleKey="notFound.noAccess"
288+
shouldShowCloseButton={false}
289+
shouldShowBackButton={this.props.isSmallScreenWidth}
290+
onBackButtonPress={Navigation.goBack}
291+
shouldShowLink={false}
302292
>
303-
{headerView}
304-
{ReportUtils.isTaskReport(this.props.report) && this.props.isSmallScreenWidth && ReportUtils.isOpenTaskReport(this.props.report) && (
305-
<View style={[styles.borderBottom]}>
306-
<View style={[styles.appBG, styles.pl0]}>
307-
<View style={[styles.ph5, styles.pb3]}>
308-
<TaskHeaderActionButton report={this.props.report} />
293+
<OfflineWithFeedback
294+
pendingAction={addWorkspaceRoomOrChatPendingAction}
295+
errors={addWorkspaceRoomOrChatErrors}
296+
shouldShowErrorMessages={false}
297+
needsOffscreenAlphaCompositing
298+
>
299+
{headerView}
300+
{ReportUtils.isTaskReport(this.props.report) && this.props.isSmallScreenWidth && ReportUtils.isOpenTaskReport(this.props.report) && (
301+
<View style={[styles.borderBottom]}>
302+
<View style={[styles.appBG, styles.pl0]}>
303+
<View style={[styles.ph5, styles.pb3]}>
304+
<TaskHeaderActionButton report={this.props.report} />
305+
</View>
309306
</View>
310307
</View>
311-
</View>
312-
)}
313-
</OfflineWithFeedback>
314-
{Boolean(this.props.accountManagerReportID) && ReportUtils.isConciergeChatReport(this.props.report) && this.state.isBannerVisible && (
315-
<Banner
316-
containerStyles={[styles.mh4, styles.mt4, styles.p4, styles.bgDark]}
317-
textStyles={[styles.colorReversed]}
318-
text={this.props.translate('reportActionsView.chatWithAccountManager')}
319-
onClose={this.dismissBanner}
320-
onPress={this.chatWithAccountManager}
321-
shouldShowCloseButton
322-
/>
323-
)}
324-
<DragAndDropProvider isDisabled={!this.isReportReadyForDisplay()}>
325-
<View
326-
style={[styles.flex1, styles.justifyContentEnd, styles.overflowHidden]}
327-
onLayout={(event) => {
328-
// Rounding this value for comparison because they can look like this: 411.9999694824219
329-
const skeletonViewContainerHeight = Math.round(event.nativeEvent.layout.height);
330-
331-
// Only set state when the height changes to avoid unnecessary renders
332-
if (reportActionsListViewHeight === skeletonViewContainerHeight) return;
333-
334-
// The height can be 0 if the component unmounts - we are not interested in this value and want to know how much space it
335-
// takes up so we can set the skeleton view container height.
336-
if (skeletonViewContainerHeight === 0) {
337-
return;
338-
}
339-
reportActionsListViewHeight = skeletonViewContainerHeight;
340-
this.setState({skeletonViewContainerHeight});
341-
}}
342-
>
343-
{this.isReportReadyForDisplay() && !isLoadingInitialReportActions && !isLoading && (
344-
<ReportActionsView
345-
reportActions={this.props.reportActions}
346-
report={this.props.report}
347-
isComposerFullSize={this.props.isComposerFullSize}
348-
parentViewHeight={this.state.skeletonViewContainerHeight}
349-
policy={policy}
350-
/>
351308
)}
352-
353-
{/* Note: The report should be allowed to mount even if the initial report actions are not loaded. If we prevent rendering the report while they are loading then
354-
we'll unnecessarily unmount the ReportActionsView which will clear the new marker lines initial state. */}
355-
{(!this.isReportReadyForDisplay() || isLoadingInitialReportActions || isLoading) && (
356-
<ReportActionsSkeletonView containerHeight={this.state.skeletonViewContainerHeight} />
357-
)}
358-
359-
{this.isReportReadyForDisplay() && (
360-
<>
361-
<ReportFooter
362-
pendingAction={addWorkspaceRoomOrChatPendingAction}
363-
isOffline={this.props.network.isOffline}
309+
</OfflineWithFeedback>
310+
{Boolean(this.props.accountManagerReportID) && ReportUtils.isConciergeChatReport(this.props.report) && this.state.isBannerVisible && (
311+
<Banner
312+
containerStyles={[styles.mh4, styles.mt4, styles.p4, styles.bgDark]}
313+
textStyles={[styles.colorReversed]}
314+
text={this.props.translate('reportActionsView.chatWithAccountManager')}
315+
onClose={this.dismissBanner}
316+
onPress={this.chatWithAccountManager}
317+
shouldShowCloseButton
318+
/>
319+
)}
320+
<DragAndDropProvider isDisabled={!this.isReportReadyForDisplay()}>
321+
<View
322+
style={[styles.flex1, styles.justifyContentEnd, styles.overflowHidden]}
323+
onLayout={(event) => {
324+
// Rounding this value for comparison because they can look like this: 411.9999694824219
325+
const skeletonViewContainerHeight = Math.round(event.nativeEvent.layout.height);
326+
327+
// Only set state when the height changes to avoid unnecessary renders
328+
if (reportActionsListViewHeight === skeletonViewContainerHeight) return;
329+
330+
// The height can be 0 if the component unmounts - we are not interested in this value and want to know how much space it
331+
// takes up so we can set the skeleton view container height.
332+
if (skeletonViewContainerHeight === 0) {
333+
return;
334+
}
335+
reportActionsListViewHeight = skeletonViewContainerHeight;
336+
this.setState({skeletonViewContainerHeight});
337+
}}
338+
>
339+
{this.isReportReadyForDisplay() && !isLoadingInitialReportActions && !isLoading && (
340+
<ReportActionsView
364341
reportActions={this.props.reportActions}
365342
report={this.props.report}
366343
isComposerFullSize={this.props.isComposerFullSize}
367-
onSubmitComment={this.onSubmitComment}
368-
policies={this.props.policies}
344+
policy={policy}
369345
/>
370-
</>
371-
)}
346+
)}
372347

373-
{!this.isReportReadyForDisplay() && (
374-
<ReportFooter
375-
shouldDisableCompose
376-
isOffline={this.props.network.isOffline}
377-
/>
378-
)}
379-
</View>
380-
</DragAndDropProvider>
381-
</FullPageNotFoundView>
382-
</ScreenWrapper>
383-
</ReportScreenContext.Provider>
348+
{/* Note: The report should be allowed to mount even if the initial report actions are not loaded. If we prevent rendering the report while they are loading then
349+
we'll unnecessarily unmount the ReportActionsView which will clear the new marker lines initial state. */}
350+
{(!this.isReportReadyForDisplay() || isLoadingInitialReportActions || isLoading) && (
351+
<ReportActionsSkeletonView containerHeight={this.state.skeletonViewContainerHeight} />
352+
)}
353+
354+
{this.isReportReadyForDisplay() && (
355+
<>
356+
<ReportFooter
357+
pendingAction={addWorkspaceRoomOrChatPendingAction}
358+
isOffline={this.props.network.isOffline}
359+
reportActions={this.props.reportActions}
360+
report={this.props.report}
361+
isComposerFullSize={this.props.isComposerFullSize}
362+
onSubmitComment={this.onSubmitComment}
363+
policies={this.props.policies}
364+
/>
365+
</>
366+
)}
367+
368+
{!this.isReportReadyForDisplay() && (
369+
<ReportFooter
370+
shouldDisableCompose
371+
isOffline={this.props.network.isOffline}
372+
/>
373+
)}
374+
</View>
375+
</DragAndDropProvider>
376+
</FullPageNotFoundView>
377+
</ScreenWrapper>
378+
</ReactionListContext.Provider>
379+
</ActionListContext.Provider>
384380
);
385381
}
386382
}

src/pages/home/ReportScreenContext.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
import {createContext} from 'react';
22

3-
const ReportScreenContext = createContext();
4-
export default ReportScreenContext;
3+
const ActionListContext = createContext();
4+
const ReactionListContext = createContext();
5+
6+
export {
7+
ActionListContext,
8+
ReactionListContext
9+
}

src/pages/home/report/ReportActionItem.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ import * as PersonalDetailsUtils from '../../../libs/PersonalDetailsUtils';
6464
import ReportActionItemBasicMessage from './ReportActionItemBasicMessage';
6565
import * as store from '../../../libs/actions/ReimbursementAccount/store';
6666
import * as BankAccounts from '../../../libs/actions/BankAccounts';
67-
import ReportScreenContext from '../ReportScreenContext';
67+
import { ReactionListContext } from '../ReportScreenContext';
6868
import Permissions from '../../../libs/Permissions';
6969

7070
const propTypes = {
@@ -127,7 +127,7 @@ function ReportActionItem(props) {
127127
const [isContextMenuActive, setIsContextMenuActive] = useState(ReportActionContextMenu.isActiveReportAction(props.action.reportActionID));
128128
const [isHidden, setIsHidden] = useState(false);
129129
const [moderationDecision, setModerationDecision] = useState(CONST.MODERATION.MODERATOR_DECISION_APPROVED);
130-
const {reactionListRef} = useContext(ReportScreenContext);
130+
const reactionListRef = useContext(ReactionListContext);
131131
const textInputRef = useRef();
132132
const popoverAnchorRef = useRef();
133133
const downloadedPreviews = useRef([]);

src/pages/home/report/ReportActionsView.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import * as ReportActionsUtils from '../../../libs/ReportActionsUtils';
1919
import reportPropTypes from '../../reportPropTypes';
2020
import PopoverReactionList from './ReactionList/PopoverReactionList';
2121
import getIsReportFullyVisible from '../../../libs/getIsReportFullyVisible';
22-
import ReportScreenContext from '../ReportScreenContext';
22+
import { ReactionListContext } from '../ReportScreenContext';
2323

2424
const propTypes = {
2525
/** The report currently being looked at */
@@ -54,10 +54,9 @@ const defaultProps = {
5454
};
5555

5656
function ReportActionsView(props) {
57-
const context = useContext(ReportScreenContext);
5857

5958
useCopySelectionHelper();
60-
59+
const reactionListRef = useContext(ReactionListContext)
6160
const didLayout = useRef(false);
6261
const didSubscribeToReportTypingEvents = useRef(false);
6362
const hasCachedActions = useRef(_.size(props.reportActions) > 0);
@@ -189,7 +188,7 @@ function ReportActionsView(props) {
189188
loadMoreChats={loadMoreChats}
190189
policy={props.policy}
191190
/>
192-
<PopoverReactionList ref={context.reactionListRef} />
191+
<PopoverReactionList ref={reactionListRef} />
193192
</>
194193
);
195194
}

0 commit comments

Comments
 (0)