首页 > 解决方案 > 当ipad方向从横向更改为纵向时如何将变量设置为false,反之亦然使用javascript并做出反应?

问题描述

当 iPad 方向使用 react 和 javascript 从横向更改为纵向以及从纵向更改为横向时,我想将变量设置为 false。

我有两个状态变量 isPopupOpen,isClicked 最初设置为 false。单击按钮时,这些设置为 true。当用户单击 Popup 之外的任何位置时,这些状态 isPopupOpen 和 isClicked 设置为 false。

下面是我的代码,它工作正常。

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>
    }

};

现在的问题是,当用户在横向模式下使用 iPad 单击弹出窗口打开的按钮时,现在没有关闭弹出窗口切换到纵向模式,弹出窗口会自行关闭。现在,当用户单击按钮时,弹出窗口不会出现。

我认为这里的问题是,当用户切换到纵向模式时,弹出窗口会自行关闭,并且 isClicked 状态值设置为 false。但 isPopupOpen 状态值仍然为真。

我认为由于 isPopupOpen 是从其他组件传递的,因此它的值不会在切换到不同模式时自动设置为 false。而 isClicked 状态值设置为 false。

我怎么解决这个问题?当用户切换模式时,如何将 isPopupOpen 也设置为 false。React.useEffect 是否以某种方式用于这种情况。

有人可以帮我解决这个问题吗?谢谢。

编辑:

根据提供的答案,我尝试过这样的事情

const onOrientationChange = React.useCallback(() => {
    setIsPopupOpen(false);
}, [setIsPopupOpen]);
React.useEffect(() => {
    window.addEventListener('orientationchange', onOrientationChange);
    return () => {
       window.removeEventListener('orientationchange', onOrientationChange);
    };
}, [onOrientationChange]);

但这仍然没有显示弹出窗口。

标签: javascriptreactjs

解决方案


您可以监听orientationchange事件。像所有发生在 React 域之外的事件的事件处理程序一样,您可以在useEffect没有依赖关系的钩子回调中将其连接一次,并在获得卸载回调时断开它:

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
);

如果您有几个 linting 解决方案中的任何一个,他们可能会抱怨您没有在该调用setIsPopupOpen中列为依赖项。useEffect不这样做应该是安全的,因为状态设置器应该是稳定的(在组件的生命周期内不会改变)。来自的useState那些。由于您是通过 props 接收您的,因此您需要确保该 setter 确实稳定(例如,确保它来自useState使用您的组件的组件)。

如果您只是将它添加到依赖数组中,并且它会定期更改,您将收到虚假调用,说方向已更改。如果您无法获得该保证,则可以处理该问题,但工作量更大:

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>
    }

};

请注意,该window.orientation属性被 MDN 描述为“不再推荐”,并且事件和属性都由兼容性规范描述。不过,直到或除非传感器 API 出现,我无法想象移动浏览器会放弃对它们的支持。


推荐阅读