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

时间:2018-04-18 14:52:51

标签: reactjs

我在ReactJS有一个网站。我希望每当我的标签聚焦或隐藏时都会收到回调。为此我遇到了Page Visibility API,但我无法弄清楚如何在ReactJS中使用它。

我在哪个生命周期方法中为此注册了回调?

6 个答案:

答案 0 :(得分:4)

这应该有效:

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

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

onFocus = () => {
    //
}

编辑:同样适用于“模糊”,它应该适用于标签隐藏的时候。

检查@Assaf的钩子使用答案。

答案 1 :(得分:2)

这些都不能很好地满足我的需要,这是一种检测用户是否在选项卡之间切换或通过双击任务栏中的图标最小化浏览器的方法。

他们要么多次触发,但确实注册了正确的状态,从任务栏图标最小化时不起作用,或者只是没有设法一个接一个地跟上多个动作。

看到每次焦点改变时我都需要发出服务器请求,上述情况有点“不”。

所以这就是我所做的:

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 上都进行了测试,您需要做的就是在主组件中或您需要的任何地方对其进行初始化,它将跟踪所有这些场景的窗口焦点,它会每个动作只发出一个服务器请求。

答案 2 :(得分:1)

从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);
    // Specify how to clean up after this effect:
    return () => {
      window.removeEventListener('focus', onFocus);
      window.removeEventListener('blur', onBlur);
    };
  });

  return <></>;
};

export default WindowFocusHandler;

答案 3 :(得分:0)

找到了这个图书馆。可能会有帮助... https://www.npmjs.com/package/react-page-visibility 这是我用它来解决您的问题的方式

\DateTime

答案 4 :(得分:0)

没有可靠的方法来检查它,因此您需要将几种方法结合在一起。这是react-hook的上下文

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(() => {
    document.addEventListener('visibilitychange', handleActivity)
    document.addEventListener('blur', () => handleActivity(false))
    window.addEventListener('blur', () => handleActivity(false))
    window.addEventListener('focus', () => handleActivity(true))
    document.addEventListener('focus', () => handleActivity(true))

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

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

答案 5 :(得分:0)

更完整,更优化的挂钩:

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
}