React Custom Hook: useOrientation
This challenge asks you to build a custom React hook, useOrientation, that elegantly detects and reports the current screen orientation (portrait or landscape) of a user's device. This is incredibly useful for creating responsive UIs that adapt their layout and behavior based on how a user is holding their device, enhancing user experience across various screen sizes and orientations.
Problem Description
You need to create a custom React hook named useOrientation that exposes the current screen orientation. This hook should:
- Detect Orientation: Accurately determine if the device is in "portrait" or "landscape" mode.
- Provide State: Return the current orientation as a string (
"portrait"or"landscape"). - Update Dynamically: Automatically update the orientation state when the device's orientation changes.
- Handle Initial State: Set the initial orientation correctly when the component using the hook mounts.
Key Requirements:
- Hook Signature: The hook should have the signature
useOrientation(): Orientation. - Return Type: The
Orientationtype should be a union of"portrait"and"landscape". - Event Listener: You will need to listen to the
resizeevent on thewindowobject to detect orientation changes. - Orientation Logic: Determine orientation based on
window.innerWidthandwindow.innerHeight.
Expected Behavior:
- When the hook is first used, it should return the current orientation.
- If the user rotates their device from portrait to landscape, the hook's returned value should update from
"portrait"to"landscape". - If the user rotates their device from landscape to portrait, the hook's returned value should update from
"landscape"to"portrait".
Edge Cases:
- Server-Side Rendering (SSR): The hook should gracefully handle environments where
windowis not available (e.g., during SSR). In such cases, it should return a default orientation (e.g.,"portrait"orundefinedif you prefer to signal that orientation cannot be determined). - Initial Measurement: Ensure the initial measurement of width and height is correct.
Examples
Example 1:
// Assume the device is wider than it is tall initially
const currentOrientation = useOrientation();
// currentOrientation would be "landscape"
Explanation: In this scenario, window.innerWidth is greater than window.innerHeight, indicating a landscape orientation.
Example 2:
// Assume the device is taller than it is wide initially
const currentOrientation = useOrientation();
// currentOrientation would be "portrait"
Explanation: Here, window.innerHeight is greater than window.innerWidth, indicating a portrait orientation.
Example 3:
// Imagine the user rotates their device from portrait to landscape
// Initially:
// const orientation1 = useOrientation(); // orientation1 === "portrait"
// After rotation:
// const orientation2 = useOrientation(); // orientation2 === "landscape"
Explanation: The hook correctly updates its state upon the resize event triggered by the device rotation.
Constraints
- The hook must be implemented in TypeScript.
- It should not rely on any external libraries.
- Performance: The event listener should be cleaned up when the component unmounts to prevent memory leaks.
Notes
- Consider using
useStateto manage the orientation state within the hook. - Remember to use
useEffectto set up and clean up the event listener. - The logic for determining portrait vs. landscape is typically:
- Portrait:
window.innerHeight > window.innerWidth - Landscape:
window.innerWidth >= window.innerHeight
- Portrait:
- You'll need to define a type for the orientation string.