-
Notifications
You must be signed in to change notification settings - Fork 3k
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
[Fix] preserve sidebar active report highlight between tabs #8227
[Fix] preserve sidebar active report highlight between tabs #8227
Conversation
PR Reviewer Checklist
|
Working on finding any performance related issues |
// This is usually needed after login/create account and re-launches | ||
return ( | ||
<BaseDrawerNavigator | ||
drawerContent={() => ( |
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.
Avoid using arrow function callbacks in components that are expensive to re-render. React will re-render this component since each time the parent renders it creates a new instance of that function. Alternative: Bind the method in the constructor instead - https://github.com/Expensify/App/blob/main/PERFORMANCE.md#react-performance-tips
@mdneyazahmad Let's remove the arrow function
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.
We can not remove it because we have to pass currentlyViewedReportID
. The other option is to use Context
. May be, we can make SidebarScreen
PureComponent
.
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 need your help here. What do you think @rushatgabhane ?
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.
If I'm not wrong, making it a pure component won't help because we have an arrow function.
Anyway, regarding removing the arrow function. It might not make a difference. (I'll verify this once again)
So let's do nothing here
src/pages/home/ReportScreen.js
Outdated
@@ -87,7 +90,7 @@ function getReportID(route) { | |||
return Number.parseInt(params.reportID, 10); | |||
} | |||
|
|||
class ReportScreen extends React.Component { | |||
class ReportScreen extends React.PureComponent { |
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 wanna know why you've made this a PureComponent.
We should only bother with PureComponent if we're noticing performance problems and have determined the reason of unnecessary re-renders.
Performance.diffObject()
in componentDidUpdate()
should help you determine this.
ref: https://github.com/Expensify/App/blob/main/PERFORMANCE.md#reconciliation
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.
https://reactnavigation.org/docs/screen#children
Note: By default, React Navigation applies optimizations to screen components to prevent unnecessary renders. Using a render callback removes those optimizations. So if you use a render callback, you'll need to ensure that you use React.memo or React.PureComponent for your screen components to avoid performance issues.
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.
@mdneyazahmad I don't find that satisfactory.
Again, we should only bother with PureComponent if we're noticing performance problems and have determined the reason of unnecessary re-renders.
- Does PureComponent reduce number of re-renders? Please provide some kind of verification for this
- PureComponent only does a shallow comparison, so what side-effects (if any) are expected? https://60devs.com/pure-component-in-react.html
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.
@Beamanator can you please buddy check what I've said above #8227 (comment)
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.
Agreed @rushatgabhane - The main port of using React.PureComponent would be "to avoid performance issues" right? But if there's no performance gains we don't need to make that change. So please only make this change if we know (if you can prove) there's some benefits 👍
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 will remove PureComponent
here.
@mdneyazahmad Do we still need |
I think, we need Line 207 in b347866
|
@@ -296,9 +296,6 @@ export default compose( | |||
network: { | |||
key: ONYXKEYS.NETWORK, | |||
}, | |||
currentlyViewedReportID: { | |||
key: ONYXKEYS.CURRENTLY_VIEWED_REPORTID, |
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.
Rajat pointed out in 1:1 that currentlyViewedReportID
both in Onyx and state is confusing.
@mdneyazahmad when using a single tab, the Onyx key currentlyViewedReportID
is in sync with the state.
But when using multiple tabs, this Onyx key has the value of the most recently viewed report.
What do you think of renaming this key to something like mostRecentlyViewedReportID
.
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.
Agree I also figured out this issue when proposing the solution.
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 renaming currentlyViewedReportID
to mostRecentlyViewedReportID
in onyx
and currentlyViewedReportID
is fine in state. What do you think?
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.
sounds good
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.
We should be adding "rename" migration anytime we change an Onyx key so the old value transfers to the new key name. But maybe not worth the effort in this case...
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.
Thanks! TIL about migrations
We'll get it done once the performance issue is addressed.
Updated |
Sorry for the delay, I'll review this tomorrow. |
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.
Just passing through, but these changes look potentially dangerous as they are changing our lower level navigation code. Can we think of alternatives...?
@@ -71,9 +71,10 @@ class BaseDrawerNavigator extends Component { | |||
<Drawer.Screen | |||
key={screen.name} | |||
name={screen.name} | |||
component={screen.component} |
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.
Pretty sure this is the recommended practice for rendering a screen component. Why are we changing 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.
In this case we have to pass currentlyViewedReportID
across ReportScreen
and Sidebar
. If we use component={Screen}
we can not pass this variables, react-navigation
provides one more option for screen component that is to use render props. This way we can pass this state variables to the ReportScreen
but this is not the recommended way to pass variables it instead recommends to use Context
api for the same. If we use render props we will lose the optimizations applied by the library and we have to manually handle re-rendering of the screen component and also it suggests to use PureComponent
in this case.
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.
source: https://reactnavigation.org/docs/screen/#children
@mdneyazahmad makes sense. Thanks for the context.
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.
@Beamanator what should we do here? Is it okay to use Context
API? That's the closest thing to our previous implementation.
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'm kinda lost here. Why does this all need to happen at such a low level and why are we duplicating Onyx data in the MainDrawerNavigator
state
instead of just referencing the value that is stored in Onyx and have the SidebarLinks update when it changes?
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.
It works without changing this name but lastViewedReportID makes much sense here. User can open multiple reports but it will contain the id of last report opened.
Please do not make this change, thanks!
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 solution 3 is a good one. It might be needed in the future. Onyx is always the easiest way to manage updates.
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.
Thanks for the solution 3 and all the help, it is exactly what we need.
@mdneyazahmad let's get it done! :)
(Also, P/S format for the win! Will def use it more)
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.
It works!
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.
We need only this change
Lines 24 to 26 in 43910fe
safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], | |
captureMetrics: Metrics.canCaptureOnyxMetrics(), | |
initialKeyStates: { |
captureMetrics: Metrics.canCaptureOnyxMetrics(),
+ keysToDisableSyncEvents: [ONYXKEYS.CURRENTLY_VIEWED_REPORTID],
I will create a pr to react-native-onyx
to add the feature as suggested my @marcaaron
children: props => ( | ||
<ReportScreen | ||
setCurrentlyViewedReportID={this.setCurrentlyViewedReportID} | ||
/* eslint-disable-next-line react/jsx-props-no-spreading */ | ||
{...props} | ||
/> | ||
), | ||
initialParams, | ||
}, |
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.
IMO, Really a bad way of doing things. No prop updates should be passed to the Screen components this way. It will create a performance issue.
We have decided to close this PR because implementation has changed and this is now handled here #8759 |
Details
When opened multiple report in different tabs, preserve the active report highlighting on sidebar (web only).
Fixed Issues
$ #7792
Tests
PR Review Checklist
Contributor (PR Author) Checklist
### Fixed Issues
section aboveTests
sectionQA steps
sectionsrc/languages/*
filesSTYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)/** comment above it */
displayName
property(i.e.
StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG
)PR Reviewer Checklist
### Fixed Issues
section aboveTests
sectionQA steps
sectionsrc/languages/*
filesSTYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)/** comment above it */
displayName
property(i.e.
StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG
)QA Steps
Screenshots
Web
web.mp4
Mobile Web
mweb.mp4
Desktop
desktop.mp4
iOS
ios.mp4
Android
android.mp4