Implementing a Custom useMediaQuery Hook in React
The useMediaQuery hook is a powerful tool in React for reacting to changes in media queries. This challenge asks you to implement your own version of this hook, allowing components to dynamically adjust their behavior based on the current viewport size and media query conditions. This is useful for creating responsive user interfaces that adapt seamlessly to different screen sizes and devices.
Problem Description
You are tasked with creating a custom useMediaQuery hook in React using TypeScript. This hook should accept a media query string as an argument and return a boolean value indicating whether the media query currently matches. The hook should subscribe to changes in the media query and update its state accordingly, triggering re-renders of any components using it.
What needs to be achieved:
- Create a reusable
useMediaQueryhook that takes a media query string as input. - The hook should return a boolean value representing whether the media query matches.
- The hook should automatically update its state when the media query status changes.
- The hook should handle initial mounting and unmounting correctly.
Key Requirements:
- The hook must use the
window.matchMediaAPI to determine if the media query matches. - The hook must use the
useEffecthook to subscribe to media query changes and update its state. - The hook must handle the initial state correctly when the component mounts.
- The hook must clean up the event listener when the component unmounts to prevent memory leaks.
- The hook must be written in TypeScript.
Expected Behavior:
- When the component mounts, the hook should immediately evaluate the media query and set its state accordingly.
- When the media query status changes (e.g., the user resizes the window), the hook should update its state and trigger a re-render of the component.
- When the component unmounts, the hook should unsubscribe from media query changes.
Edge Cases to Consider:
- Invalid Media Query: The
matchMediaAPI can return null if the media query is invalid. Your hook should handle this gracefully (e.g., by returningfalseor throwing an error). - Server-Side Rendering (SSR): The
windowobject is not available on the server. Your hook should handle this situation by returning a default value (e.g.,false) or by conditionally executing the media query logic only on the client-side. - Multiple Media Queries: The hook should handle a single media query string. Consider how to handle potential errors if the string is malformed.
Examples
Example 1:
Input: mediaQuery = "(max-width: 768px)"
Output: true (if the viewport width is less than or equal to 768px)
Explanation: The hook evaluates the media query and returns true because the viewport width satisfies the condition.
Example 2:
Input: mediaQuery = "(min-width: 992px)"
Output: false (if the viewport width is less than 992px)
Explanation: The hook evaluates the media query and returns false because the viewport width does not satisfy the condition.
Example 3: (Edge Case - Invalid Media Query)
Input: mediaQuery = "invalid-media-query"
Output: false
Explanation: The hook receives an invalid media query string. `window.matchMedia` returns null, and the hook gracefully returns false.
Constraints
- The hook must be written in TypeScript.
- The hook must use the
window.matchMediaAPI. - The hook must be compatible with React 17 or higher.
- The hook should avoid unnecessary re-renders.
- The hook should handle SSR gracefully (returning a default value when
windowis not available).
Notes
- Consider using the
useEffecthook with a cleanup function to manage the media query listener. - The
matchMediaAPI returns aMediaQueryListobject, which has aaddEventListenerandremoveEventListenermethod for listening to changes. - Think about how to handle the initial state of the hook when the component mounts.
- You can use a functional component and React hooks to implement the hook.
- Focus on creating a clean, readable, and well-documented hook.