-
-
Notifications
You must be signed in to change notification settings - Fork 32.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
[withWidth] Migrate to hooks #15678
[withWidth] Migrate to hooks #15678
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import React from 'react'; | ||
import json2mq from 'json2mq'; | ||
import useMediaQuery from '@material-ui/core/useMediaQuery'; | ||
|
||
export default function JavaScriptMedia() { | ||
const matches = useMediaQuery( | ||
json2mq({ | ||
minWidth: 600, | ||
}), | ||
); | ||
|
||
return <span>{`{ minWidth: 600 } matches: ${matches}`}</span>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,40 +3,54 @@ import React from 'react'; | |
// This variable will be true once the server-side hydration is completed. | ||
let hydrationCompleted = false; | ||
|
||
function deepEqual(a, b) { | ||
return a.length === b.length && a.every((item, index) => item === b[index]); | ||
} | ||
|
||
function useMediaQuery(queryInput, options = {}) { | ||
const query = queryInput.replace('@media ', ''); | ||
const multiple = Array.isArray(queryInput); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just seeing this since it was not obvious that any implementation changed from the PR title. What is the use case for this? media queries already support combining multiple queries with boolean logic. This bloats the code a lot. It's nowhere documented that this doesn't support changing the number of queries provided. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The use case is useWidth. I have first tried to implement it with the existing
And yet, it returns a single boolean.
It should be supported. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Did you profile it?
Can always use multiple hooks. No need to overload the code.
It is passed as a dependency errors to hooks. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The withWith() higher-order component was making his wrapped component render 10 times. The performance impact is not the only dimension to consider. The more renders, the harder debugging experience for people using this higher order component. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change wasn't released yet. It's not too late to revert it if you don't feel confident with the direction. You can play with the alternative here: https://material-ui.com/components/use-media-query/#migrating-from-withwidth. Maybe if we ignore the dynamic breakpoint occurrence, and that we use an intermediary pure component to remove the redundant renders, it would work better. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An interesting implementation to benchmark against: https://github.com/streamich/use-media/blob/master/src/index.ts. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, I will give it a second try. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can't find a way to deduplicate the renders. Notice that I haven't updated the |
||
let queries = multiple ? queryInput : [queryInput]; | ||
queries = queries.map(query => query.replace('@media ', '')); | ||
|
||
const { defaultMatches = false, noSsr = false, ssrMatchMedia = null } = options; | ||
|
||
const [matches, setMatches] = React.useState(() => { | ||
if (hydrationCompleted || noSsr) { | ||
return window.matchMedia(query).matches; | ||
return queries.map(query => window.matchMedia(query).matches); | ||
} | ||
if (ssrMatchMedia) { | ||
return ssrMatchMedia(query).matches; | ||
return queries.map(query => ssrMatchMedia(query).matches); | ||
} | ||
|
||
// Once the component is mounted, we rely on the | ||
// event listeners to return the correct matches value. | ||
return defaultMatches; | ||
return queries.map(() => defaultMatches); | ||
}); | ||
|
||
React.useEffect(() => { | ||
hydrationCompleted = true; | ||
|
||
const queryList = window.matchMedia(query); | ||
setMatches(queryList.matches); | ||
const queryLists = queries.map(query => window.matchMedia(query)); | ||
setMatches(prev => { | ||
const next = queryLists.map(queryList => queryList.matches); | ||
return deepEqual(prev, next) ? prev : next; | ||
}); | ||
|
||
function handleMatchesChange(event) { | ||
setMatches(event.matches); | ||
function handleMatchesChange() { | ||
setMatches(queryLists.map(queryList => queryList.matches)); | ||
} | ||
|
||
queryList.addListener(handleMatchesChange); | ||
queryLists.forEach(queryList => { | ||
queryList.addListener(handleMatchesChange); | ||
}); | ||
return () => { | ||
queryList.removeListener(handleMatchesChange); | ||
queryLists.forEach(queryList => { | ||
queryList.removeListener(handleMatchesChange); | ||
}); | ||
}; | ||
}, [query]); | ||
}, queries); // eslint-disable-line react-hooks/exhaustive-deps | ||
|
||
return matches; | ||
return multiple ? matches : matches[0]; | ||
} | ||
|
||
export function testReset() { | ||
|
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 come back to it in two months, we will be able to use the Google Analytics events to better answer this question: Should we have json2mq built-in?