I want to set a variable to false when iPad orientation is changed from landscape to portrait and from portrait to landscape using react and javascript.
I have two state variables isPopupOpen, isClicked set to false initially. when the button is clicked these are set to true. when the user clicks anywhere outside Popup these states isPopupOpen and isClicked are set to false.
below is my code and it works fine.
function Parent({setIsPopupOpen, isPopupOpen}: Props) {
const {isClicked, setIsClicked} = React.useState(false);
const handleButtonClick = () => {
setIsPopupOpen(!isPopupOpen);
setIsClicked(!isClicked);
}
return () {
<button onClick={handleButtonClick}>click me </button>
<Popup>
<Overlay onClick={() => {
setIsPopupOpen(false);
setIsClicked(false);
}/>
</Popup>
}
};
Now the problem is when the user uses iPad in landscape mode clicks a button the popup opens, now without closing popup switches to portrait mode the popup closes on its own. now when the user clicks on the button the popup doesn't show up.
I think the problem here is, when the user switches to portrait mode, the popup closes on its own and the isClicked state value sets to false. but the isPopupOpen state value is still true.
I think since isPopupOpen is passed from other components, its value is not set to false automatically on switching to different modes. whereas isClicked state value is set to false.
How can I solve this problem? How can I set isPopupOpen to false too when the user switches modes. does React.useEffect somehow be used for this case.
Could someone help me with this? thanks.
EDIT:
based on the answer provided I have tried something like this
const onOrientationChange = React.useCallback(() => {
setIsPopupOpen(false);
}, [setIsPopupOpen]);
React.useEffect(() => {
window.addEventListener('orientationchange', onOrientationChange);
return () => {
window.removeEventListener('orientationchange', onOrientationChange);
};
}, [onOrientationChange]);
But this still doesn't show the popup.
You can listen for the orientationchange
event. Like all event handlers for events that occur outside React's domain, you'd hook it up once in a useEffect
hook callback with no dependencies and disconnect it when you get the unmounting callback:
useEffect(
() => {
// Component is being mounted, add listener
function onOrientationChange(event) {
// Or if you just want to set the flag false:
setIsPopupOpen(false);
}
window.addEventListener("orientationchange", onOrientationChange);
return () => {
// Component is being unmounted, remove listener
window.removeEventListener("orientationchange", onOrientationChange);
};
},
[] // <== No deps = only on mount
);
If you have any of several linting solutions in place, they may complain about your not listing setIsPopupOpen
as a dependency in that useEffect
call. It should be safe not to do so, because state setters should be stable (not change across the duration of a component's lifecycle). The ones from useState
are. Since you're receiving yours via props, you'll need to be sure that that setter is indeed stable (for instance, make sure it's from useState
in the component that's using your component).
If you just added it to the dependency array, and it gets changed regularly, you'll get spurious calls saying the orientation changed. It's possible to deal with that if you can't get that guarantee, but it's more work:
function Parent({setIsPopupOpen, isPopupOpen}: Props) {
const {isClicked, setIsClicked} = React.useState(false);
const [angle, setAngle] = React.useState(window.orientation);
const handleButtonClick = () => {
setIsPopupOpen(!isPopupOpen);
setIsClicked(!isClicked);
};
React.useEffect(
() => {
// Component is being mounted, add listener
function onOrientationChange(event) {
const newAngle = window.orientation;
if (newAngle !== angle) {
setAngle(newAngle);
setIsPopupOpen(false);
}
}
window.addEventListener("orientationchange", onOrientationChange);
return () => {
// Component is being unmounted, remove listener
window.removeEventListener("orientationchange", onOrientationChange);
};
},
[setIsPopupOpen, angle]
);
return () {
<button onClick={handleButtonClick}>click me </button>
<Popup>
<Overlay onClick={() => {
setIsPopupOpen(false);
setIsClicked(false);
}/>
</Popup>
}
};
Note that the window.orientation
property is described as "no longer recommended" by MDN, and both the event and the property are described by the compatibility specification. Until or unless the Sensors API happens, though, I can't imagine mobile browsers will drop support for them.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments