-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Separate ReportScreenContext to prevent cyclic re-renders #25948
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
Conversation
CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅ |
ba7f424
to
8de3031
Compare
8de3031
to
3be5e69
Compare
I have read the CLA Document and I hereby sign the CLA |
@ospfranco can you please link issue correctly in issue description? And please fix lint Example:
|
I have update the issue, there was no issue before |
@tgolen feel free to review this one if you interested |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please make a couple of these changes?
I would also appreciate if the PR or the associated GH had a bit more information that:
- Proves the extra re-rendering exists in the first place (I just have to take your word for it, which I can do, but 1 year in the future it might not be so great)
- Proves the extra re-rendering is no longer happening
src/pages/home/ReportScreen.js
Outdated
</FullPageNotFoundView> | ||
</ScreenWrapper> | ||
</ReportScreenContext.Provider> | ||
{/* 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The report should be allowed to mount
Can you please clarify in this comment what "the report" is? Is it:
- ReportActionsSkeletonView
- ReportFooter
- ReportFooter
- All three?
- Something else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All these are part of linting (the component it is now wrapped into a new context provider), I have not changed or touched the internal logic. I can do it if you want, but it falls out of the scope of the performance improvements
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't you lucky that you stumbled into this code? 😀
I guess it's not a blocker for this particular PR, but I am always happy to see it when people leave the code better than how they found it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, I will take care of it then :)
src/pages/home/ReportScreen.js
Outdated
<View | ||
style={[styles.flex1, styles.justifyContentEnd, styles.overflowHidden]} | ||
onLayout={(event) => { | ||
// Rounding this value for comparison because they can look like this: 411.9999694824219 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move this logic to a method outside of the return()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All these are part of linting (the component it is now wrapped into a new context provider), I have not changed or touched the internal logic. I can do it if you want, but it falls out of the scope of the performance improvements
src/pages/home/ReportScreen.js
Outdated
{this.isReportReadyForDisplay() && ( | ||
<> | ||
<ReportFooter | ||
pendingAction={addWorkspaceRoomOrChatPendingAction} | ||
isOffline={this.props.network.isOffline} | ||
reportActions={this.props.reportActions} | ||
report={this.props.report} | ||
isComposerFullSize={this.props.isComposerFullSize} | ||
onSubmitComment={this.onSubmitComment} | ||
policies={this.props.policies} | ||
/> | ||
</> | ||
)} | ||
|
||
{!this.isReportReadyForDisplay() && ( | ||
<ReportFooter | ||
shouldDisableCompose | ||
isOffline={this.props.network.isOffline} | ||
/> | ||
)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should be a ternary
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All these are part of linting (the component it is now wrapped into a new context provider), I have not changed or touched the internal logic. I can do it if you want, but it falls out of the scope of the performance improvements
src/pages/home/ReportScreen.js
Outdated
</ReportScreenContext.Provider> | ||
{/* 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 | ||
we'll unnecessarily unmount the ReportActionsView which will clear the new marker lines initial state. */} | ||
{(!this.isReportReadyForDisplay() || isLoadingInitialReportActions || isLoading) && ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think making this a ternary with the block above it will improve readability. It makes it easier to understand that the intention is that either one or the other should be displayed, never both.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All these are part of linting (the component it is now wrapped into a new context provider), I have not changed or touched the internal logic. I can do it if you want, but it falls out of the scope of the performance improvements
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ReportScreen is now refactored to functional component. Please fix conflict and lint
# Conflicts: # src/pages/home/ReportScreen.js
Done! Thanks! |
For commit 3be5e69 (separating the contexts to prevent cyclic re-renders), here is the react devtools trace, you can see before the change there are at least 7 renders, this is also a parent component, so it triggers a cascade of re-renders on the children. Afer the change this has gone down to 3. |
For commit 6125c38 (Get rid of full list re-render when marking messages as unread) Here is the trace before and after You can see a reduction of 2 renders, but again this being a parent component it triggers a re-render of the entire list elements |
Thanks for those images and showing the change to the re-renders! |
Details
We are trying to optimize the ReportScreen. This is the first issue I found where a shared context to manipulate certain lists would cause parent components to re-render causing a cascade of cyclic renders.
By separating the context we limit the re-renders to the part of the tree that consume the specific contexts and win back some render cycles.
Fixed Issues
$ #26087
Tests
Offline tests
None needed in offline mode
QA Steps
PR Author Checklist
### Fixed Issues
section aboveTests
sectionOffline steps
sectionQA steps
sectiontoggleReport
and notonIconClick
)myBool && <MyComponent />
.src/languages/*
files and using the translation methodWaiting for Copy
label for a copy review on the original GH to get the correct copy.STYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)/** comment above it */
this
properly so there are no scoping issues (i.e. foronClick={this.submit}
the methodthis.submit
should be bound tothis
in the constructor)this
are necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);
ifthis.submit
is never passed to a component event handler likeonClick
)StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)
)Avatar
is modified, I verified thatAvatar
is working as expected in all cases)ScrollView
component to make it scrollable when more elements are added to the page.main
branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTest
steps.Screenshots/Videos
Web
Mobile Web - Chrome
Mobile Web - Safari
Desktop
iOS
Android
Here is a video showing the Report screen emoji list is still working.
Android.mp4