-
Notifications
You must be signed in to change notification settings - Fork 350
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
Guard against matchMedia access during initial render #1459
Conversation
GeraldRequired Reviewers
Don't want to be involved in this pull request? Comment |
npm Snapshot: PublishedGood news!! We've packaged up the latest commit from this PR (cea126a) and published it to npm. You Example: yarn add @khanacademy/perseus@PR1459 If you are working in Khan Academy's webapp, you can run: ./dev/tools/bump_perseus_version.sh -t PR1459 |
this._mounted && | ||
mediaQueryIsMatched("(prefers-reduced-motion: no-preference)"); |
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.
note: We don't want animation on by default on initial render in case the user has turned it off (long term, it would be useful if this also could be overridden by webapp profile setting too).
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 confused how this fixes things. The mediaQueryIsMatched
function guards against window.matchMedia
not being a function. Is that helper written wrong or is the fix more about only running on a mounted 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.
This is a subtle thing, but we don't just want to guard against it being accessed; the initial render on both server and client must be identical, so we don't want to use matchMedia
at all on first render as the client could give a different rendered result than the server.
@@ -106,7 +119,7 @@ export default class Marker extends React.Component<Props> { | |||
} else if (showPulsate) { | |||
iconStyles = [ | |||
styles.markerPulsateBase, | |||
shouldReduceMotion() | |||
this._mounted && shouldReduceMotion() |
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.
note: We don't want animation on by default on initial render in case the user has turned it off (long term, it would be useful if this also could be overridden by webapp profile setting too).
const isWideImage = | ||
this.props.imageWidth / 2 > this.props.imageHeight; | ||
// Determine whether the image is wider than it is tall. | ||
const isWideImage = this.props.imageWidth / 2 > this.props.imageHeight; |
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.
note: Moved out of the loop; doesn't need recalculating multiple times.
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 fixing this up!
this._mounted && | ||
window.matchMedia(mediaQueries.xsOrSmaller.replace("@media ", "")) | ||
.matches; |
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.
note: Moved out of the loop since it won't change for each item, and modified to return false
on initial render so that it will SSR and hydrate correctly.
Size Change: +86 B (+0.01%) Total Size: 849 kB
ℹ️ View Unchanged
|
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1459 +/- ##
==========================================
+ Coverage 69.79% 70.12% +0.33%
==========================================
Files 505 508 +3
Lines 105003 104905 -98
Branches 7548 10713 +3165
==========================================
+ Hits 73283 73565 +282
+ Misses 31536 31340 -196
+ Partials 184 0 -184
... and 151 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
|
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 changes all seem reasonable to me, thank you for figuring this out, Jeff! I'll defer to the Perseus team for final approval here, though.
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 fixes mostly make sense. I left one question and I think it would make sense to move the mediaQueryIsMatched
helper to a new file in packages/perseus/src/util
. Not a deal-breaker, but if you decide not to please let me know and I'll create a ticket to do this after the fact.
Thanks for chasing this down Jeff.
this._mounted && | ||
mediaQueryIsMatched("(prefers-reduced-motion: no-preference)"); |
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 confused how this fixes things. The mediaQueryIsMatched
function guards against window.matchMedia
not being a function. Is that helper written wrong or is the fix more about only running on a mounted component?
// Determine whether page is rendered in a narrow browser window. | ||
const isNarrowPage = | ||
this._mounted && | ||
window.matchMedia(mediaQueries.xsOrSmaller.replace("@media ", "")) |
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 usage doesn't use a helper to guard window.matchMedia
being undefined. I wonder if we should move all these checks to call a helper that guards usage properly. Would that alleviate us needing the _mounted
flag in each 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.
Guarding against it being undefined
is really a red herring; I think perhaps that check should be removed where we have it. I don't think we support any browsers that won't have it at this point, and we shouldn't be determining by that measure if we call it or not on initial render as we need that to match on both client (where it exists) and server (where it doesn't exist or might give a different response than on the client).
The _mounted
flag is the important bit to avoid having a different initial render on the client than on the server (both initial renders have to match or hydration fails)
Summary:
This PR makes sure that we don't call
matchMedia
during the initial render. This is becausematchMedia
is not available during the initial render, and calling it will throw an error.Issue: FEI-5743
Test plan: