检查浏览器选项卡是否在ReactJS中处于焦点位置

s1ag04yj  于 2023-03-17  发布在  React
关注(0)|答案(8)|浏览(166)

我有一个网站在ReactJS。我想得到一个回调每当我的标签进入焦点或隐藏。我遇到了页面可见性API的这一点,但我不能弄清楚如何使用它在ReactJS。
我应该在哪个生命周期方法中为此注册回调?

xuo3flqw

xuo3flqw1#

从React 16.8开始,使用钩子构建了这个

import React, { useEffect } from "react";

// User has switched back to the tab
const onFocus = () => {
    console.log("Tab is in focus");
};

// User has switched away from the tab (AKA tab is hidden)
const onBlur = () => {
    console.log("Tab is blurred");
};

const WindowFocusHandler = () => {
    useEffect(() => {
        window.addEventListener("focus", onFocus);
        window.addEventListener("blur", onBlur);
        // Calls onFocus when the window first loads
        onFocus();
        // Specify how to clean up after this effect:
        return () => {
            window.removeEventListener("focus", onFocus);
            window.removeEventListener("blur", onBlur);
        };
  }, []);

    return <></>;
};

export default WindowFocusHandler;

2023年5月编辑:
有一个新的visibilitychange事件对移动的web标签有more nuanced行为,如果你需要不同的行为来显示移动用户浏览他们的web标签和切换到不同的标签,你可以使用这个事件API,如下面更多的回答所述。

pvcm50d1

pvcm50d12#

这应该行得通:

componentDidMount() {
    window.addEventListener("focus", this.onFocus)
}

componentWillUnmount() {
    window.removeEventListener("focus", this.onFocus)
}

onFocus = () => {
    //
}

编辑:同样的“模糊”,它应该工作时,标签成为隐藏。
检查@Assaf的答案,了解钩子的用法。

iih3973s

iih3973s3#

没有可靠的方法来检查它,所以你需要把几个方法组合在一起。

import React, { useState, useEffect } from 'react'

export const WindowContext = React.createContext(null)

export const WindowContextProvider = props => {
  const [windowIsActive, setWindowIsActive] = useState(true)

  function handleActivity(forcedFlag) {
    if (typeof forcedFlag === 'boolean') {
      return forcedFlag ? setWindowIsActive(true) : setWindowIsActive(false)
    }

    return document.hidden ? setWindowIsActive(false) : setWindowIsActive(true)
  }

  useEffect(() => {
    const handleActivityFalse = () => handleActivity(false)
    const handleActivityTrue = () => handleActivity(true)

    document.addEventListener('visibilitychange', handleActivity)
    document.addEventListener('blur', handleActivityFalse)
    window.addEventListener('blur', handleActivityFalse)
    window.addEventListener('focus', handleActivityTrue )
    document.addEventListener('focus', handleActivityTrue)

    return () => {
      window.removeEventListener('blur', handleActivity)
      document.removeEventListener('blur', handleActivityFalse)
      window.removeEventListener('focus', handleActivityFalse)
      document.removeEventListener('focus', handleActivityTrue )
      document.removeEventListener('visibilitychange', handleActivityTrue )
    }
  }, [])

  return <WindowContext.Provider value={{ windowIsActive }}>{props.children}</WindowContext.Provider>
}
yacmzcpb

yacmzcpb4#

我找到了This library。可能会有帮助。
以下是我将如何使用它来解决您的问题

import React from 'react';
import PageVisibility from 'react-page-visibility';

class YourComponent extends React.Component {
    state = {
      isWindowInFocus: true,
    }
    componentDidMount() {
      const { isWindowInFocus } = this.props;
      if (!isWindowInFocus) {
        // do something
      }
    }

    listentoWindow = isVisible => {
      this.setState({
        isWindowInFocus: isVisible,
      });
    }
    render() {
      return (
        <PageVisibility onChange={this.listentoWindow}>
          <div>
           Your component JSX
          </div>
        </PageVisibility>
      );
    }
}
tjvv9vkg

tjvv9vkg5#

现代钩:

import { useCallback, useEffect, useState } from "react";

const useTabActive = () => {
  const [visibilityState, setVisibilityState] = useState(true);

  const handleVisibilityChange = useCallback(() => {
    setVisibilityState(document.visibilityState === 'visible');
  }, []);

  useEffect(() => {
    document.addEventListener("visibilitychange", handleVisibilityChange)
    return () => {
      document.removeEventListener("visibilitychange", handleVisibilityChange)
    }
  }, []);

  return visibilityState;
}

export default useTabActive;

用法:

const isTabActive = useTabActive();

此挂接使用Document.visibilityState

5lwkijsr

5lwkijsr6#

这些都不能很好地满足我的需要,这是一种检测用户是否在选项卡之间切换的方法,或者通过双击任务栏中的图标来最小化浏览器。
他们要么发射了多次,但没有管理注册正确的状态,没有工作时,最小化从任务栏图标或只是没有设法跟上多个行动一个接一个。
鉴于每次焦点改变时我都需要发出服务器请求,上述情况有点“不”。
这就是我所做的

const DetectChatFocus = () => {
    const [chatFocus, setChatFocus] = useState(true);

    useEffect(() => {
        const handleActivityFalse = () => {
            setChatFocus(false);
            serverRequest(false);
        };

        const handleActivityTrue = () => {
            setChatFocus(true);
            serverRequest(true);
        };

        window.addEventListener('focus', handleActivityTrue);
        window.addEventListener('blur', handleActivityFalse);

        return () => {
            window.removeEventListener('focus', handleActivityTrue);
            window.removeEventListener('blur', handleActivityFalse);
        };
    }, [chatFocus]);
};

export default DetectChatFocus;

目前这似乎工作得很好,在Chrome和Firefox上都进行了测试,你所需要做的就是在一个主组件中或任何你需要的地方初始化它,它将跟踪所有这些场景的窗口焦点,它将只对每个操作发出一个服务器请求。

5w9g7ksd

5w9g7ksd7#

更完整、更优化的钩子:

import React, { useState, useEffect } from 'react'
import _ from 'lodash'

export default function useIsWindowFocused(): boolean {
    const [windowIsActive, setWindowIsActive] = useState(true)

    const handleActivity = React.useCallback(
        _.debounce(
            (e: { type: string }) => {
                if (e?.type == 'focus') {
                    return setWindowIsActive(true)
                }
                if (e?.type == 'blur') {
                    return setWindowIsActive(false)
                }
                if (e?.type == 'visibilitychange') {
                    if (document.hidden) {
                        return setWindowIsActive(false)
                    } else {
                        return setWindowIsActive(true)
                    }
                }
            },
            100,
            { leading: false },
        ),
        [],
    )

    useEffect(() => {
        document.addEventListener('visibilitychange', handleActivity)
        document.addEventListener('blur', handleActivity)
        window.addEventListener('blur', handleActivity)
        window.addEventListener('focus', handleActivity)
        document.addEventListener('focus', handleActivity)

        return () => {
            window.removeEventListener('blur', handleActivity)
            document.removeEventListener('blur', handleActivity)
            window.removeEventListener('focus', handleActivity)
            document.removeEventListener('focus', handleActivity)
            document.removeEventListener('visibilitychange', handleActivity)
        }
    }, [])

    return windowIsActive
}
gj3fmq9x

gj3fmq9x8#

我认为查看document.visibilityState的直接状态更简单,因为它返回'visible''hidden'

const [visibilityState, setVisibilityState] = useState('visible')

useEffect(() => {
  setVisibilityState(document.visibilityState)
}, [document.visibilityState])

相关问题