-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
Component refactor: migrate PopoverWithMeasuredContent to function component #22868
Conversation
|
||
export default withWindowDimensions(PopoverWithMeasuredContent); | ||
export default React.memo(PopoverWithMeasuredContent, (prevProps, nextProps) => prevProps.isVisible && !_.isEqual(prevProps, nextProps)); |
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.
This logic is not correct. Previously this was used with the window dimensions props.
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.
@s77rt This is not a replace. We change withWindowDimensions to useWindowDimensions hook so hoc is not needed anymore. And we had a shouldComponentUpdate
here
App/src/components/PopoverWithMeasuredContent.js
Lines 97 to 105 in e2e4057
shouldComponentUpdate(nextProps, nextState) { | |
if (this.props.isVisible && (nextProps.windowWidth !== this.props.windowWidth || nextProps.windowHeight !== this.props.windowHeight)) { | |
return true; | |
} | |
// This component does not require re-render until any prop or state changes as we get the necessary info | |
// at first render. This component is attached to each message on the Chat list thus we prevent its re-renders | |
return !_.isEqual(_.omit(this.props, ['windowWidth', 'windowHeight']), _.omit(nextProps, ['windowWidth', 'windowHeight'])) || !_.isEqual(this.state, nextState); | |
} |
React.memo
with props comparing 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.
What I meant is the comparison logic is not correct. prevProps.isVisible && !_.isEqual(prevProps, nextProps)
this makes no sense and it seems to be the cause of a regression, the floating action button is broken.
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 I'd better return windowWidth/Height props to handle this update logic - if isVisible update only on dimensions change.
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.
Let's use the hook and for the React.memo()
we can omit the function parameters. The "do not update if only window dimensions change" is useless, the component will pretty much already re-render because we are passing a lot of changing data (e.g. anchorPosition is always a new object).
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.
No, this leads to a regression with browser window dimensions change. I'll fix the logic
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.
Interesting bug. We should fix that bug instead of hiding it. Any ideas yet on the root cause?
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.
@s77rt I think the root cause is that shiftedAnchorPosition left/top could be <0 on some updates. You could see it if you add console.log right before return and leave React.memo without props comparing function. So it seems to be not hiding the bug but prevent unnecessary 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.
@alexxxwork This still does not explain the root cause. Something is not right, the whole content changes.
Co-authored-by: Carlos Martins <[email protected]>
Co-authored-by: Carlos Martins <[email protected]>
@s77rt Last commit fixes a regression in popover position on browser window dimensions change. |
@alexxxwork Any update here? (regarding #22868 (comment)) |
@s77rt The content changes specifically for context menu, where PopoverWithMeasuredContent is just a wrapping component and it seems to prevent updates that cause content changes in child component - BaseReportActionContextMenu. Content changes because the number of options are determined with the filter here: App/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js Lines 93 to 103 in 6bcd184
And after some updates this filter shows only two options. This is caused by these props changing for BaseReportActionContextMenu:
Props are changing because they are in state in this component App/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js Lines 306 to 319 in 4a8b431
So I think we should also convert this component to functional to ensure no regressions arise. |
The state in PopoverReportActionMenu is cleared by this callback here:
|
@alexxxwork Can you please explain how is this component effected by others only when it's being a functional component. It's weird. I would expect identical behaviour whether this is written as a functional component or a class component. |
@s77rt There's an additional mount/unmount cycle of the component before the context menu opens if we use react.memo without a props comparing function. So when we see the context menu the state variables of the reportID in PopoverReportActionContextMenu is already "0" as if we close the context menu. So when it is updated it changes content. |
@alexxxwork Is |
@s77rt the additional mount/unmount cycle comes from PopoverWithMeasuredContent - it is called with wrong isContentMeasured value so Popover (and Modal in it) gets unmounted which was unintended by its design.
this check should run on every component update Should I add these changes and keep React.memo with props comparing? |
@alexxxwork How would changing the dependencies solve this issue? The underlying logic will stay the same. |
@s77rt the issue comes from unmounting of child components of PopoverWithMeasuredContent. What dependencies do you mean? |
@s77rt please test latest commit |
Reviewer Checklist
Screenshots/Videos |
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.
LGTM! 🚀
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
🚀 Deployed to staging by https://github.com/luacmartins in version: 1.3.46-0 🚀
|
🚀 Deployed to staging by https://github.com/luacmartins in version: 1.3.47-0 🚀
|
🚀 Deployed to production by https://github.com/marcaaron in version: 1.3.46-2 🚀
|
🚀 Deployed to production by https://github.com/Beamanator in version: 1.3.47-6 🚀
|
Details
Migrate PopoverWithMeasuredContent to function component
Fixed Issues
$ #16191
PROPOSAL: #16191 (comment)
Tests
Offline tests
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