React
by _sir
HTML
<div id="app"></div>
CSS
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
.done {
color: rgba(0, 0, 0, 0.3);
text-decoration: line-through;
}
input {
margin-right: 5px;
}
React
const reducer = (state, action) => {
if (action.type === 'RESET') {
return action.payload;
}
return {
...state,
[action.type]: action.payload,
};
};
const createInitialState = (queries) => {
const allQueries = Array.isArray(queries) ? queries : [queries];
return allQueries.reduce(
(accum, q) => ({
...accum,
[q]: window.matchMedia(q).matches,
}),
{}
);
};
/**
* Media query string or array of media queries
* @group Hooks
* @param {Array|string} queries
* @returns {boolean|Object} - If a single query is passed, returns a boolean indicating whether the query matches the current viewport. If multiple queries are passed, returns an object with the query as the key and the boolean match result as the value.
*/
const useMediaQuery = (queries) => {
const initialState = useMemo(() => createInitialState(queries), [queries]);
const [state, dispatch] = useReducer(reducer, initialState);
const firstRender = useRef(true);
useEffect(() => {
// Don't want to reset on initialRender because we start with a valid state
if (firstRender.current) {
firstRender.current = false;
return;
}
// Anytime the queries change though, reset the state with the correct values
dispatch({ type: 'RESET', payload: createInitialState(queries) });
}, [queries]);
useEffect(() => {
const queriesToMap = Array.isArray(queries) ? queries : [queries];
const listeners = queriesToMap.map((query) => {
const match = window.matchMedia(query);
const handleMediaChange = (e) => {
dispatch({ type: query, payload: e.matches });
};
match.addEventListener('change', handleMediaChange);
// Return the match and named function for cleanup in the return function below
return {
match,
handleMediaChange,
};
});
return () => {
listeners.forEach((listener) =>
...