React.js - 仅当页面处于活动状态(页面加载或重新加载)时才触发“useEffect”

IT技术 html css reactjs svg
2021-05-09 08:35:05

TL; 博士

Vanilla-JS 应用程序在用户在页面上处于活动状态时才执行代码,而 React 组件会在组件加载到 DOM 中后立即执行代码(即使用户在页面上未处于活动状态


我正在一个 React 网站上工作,并使用“CSS Transitions”创建一个 SVG 动画,该动画是通过向元素添加一个类来触发的。下面是react代码

useEffect(() => {    
function startAnimation() {
    var wrapper = document.querySelector('svg#logo');
    wrapper.classList.add('active');
}
}, []);

我最初在 Vanilla-JS 项目中创建了它(使用 jQuery 的$(document).ready()函数),然后将其转换为 React 组件。但是我注意到 Vanilla-JS 应用程序中的转换仅在页面处于活动状态时才会启动,而 React 组件会在组件加载到 DOM 中后立即启动转换(即使用户在页面上未处于活动状态)。

我知道这是因为我使用了useEffect钩子,但是我们如何获得与$(document).ready()使用 React相同的行为

下面是 Vanialla-JS 代码

$(document).ready(function () {
function logoDraw() {
  var wrapper = document.querySelector('svg#logo')
  wrapper.classList.add('active')
}

  setTimeout(logoDraw, 10)
});

更新:

  • 根据另一个问题的答案,我使用“focus”事件侦听器仅在页面处于焦点时才启动动画。但是这样做之后,如果我重新加载页面并停留在同一页面上,则不会启动转换。如果我切换标签,它只会被启动。
  • 我发现了一个相关的问题,它指出“在第一次加载页面时它已经具有焦点,因此不会引发任何事件”
1个回答

在网上搜索了几个小时后,我终于在一篇题为“利用 React 使用页面可见性 API ”的博客文章中找到了完美的答案

它做两件事之一:

  1. 检测页面是否已经处于活动状态并立即执行代码(即使重新加载也能工作
  2. 等待选项卡变为活动状态并执行代码。

该博客详细介绍了它的工作原理,Seth Corker(博客所有者)还主持了一个演示


如果页面处于活动状态,我们可以使用“页面可见性 API ”,并使用“useEffect”钩子根据需要更改任何 DOM 元素。

请在下面找到来自上述博客的工作代码的示例副本。

function getBrowserVisibilityProp() {
    if (typeof document.hidden !== "undefined") {
        // Opera 12.10 and Firefox 18 and later support
        return "visibilitychange"
    } else if (typeof document.msHidden !== "undefined") {
        return "msvisibilitychange"
    } else if (typeof document.webkitHidden !== "undefined") {
        return "webkitvisibilitychange"
    }
}

function getBrowserDocumentHiddenProp() {
    if (typeof document.hidden !== "undefined") {
        return "hidden"
    } else if (typeof document.msHidden !== "undefined") {
        return "msHidden"
    } else if (typeof document.webkitHidden !== "undefined") {
        return "webkitHidden"
    }
}

function getIsDocumentHidden() {
    return !document[getBrowserDocumentHiddenProp()]
}

function usePageVisibility() {
    const [isVisible, setIsVisible] = React.useState(getIsDocumentHidden())
    const onVisibilityChange = () => setIsVisible(getIsDocumentHidden())

    React.useEffect(() => {
        const visibilityChange = getBrowserVisibilityProp()

        document.addEventListener(visibilityChange, onVisibilityChange, false)

        return () => {
            document.removeEventListener(visibilityChange, onVisibilityChange)
        }
    })

    return isVisible
}

// Above code uses Page_Visibility_API
// Below is a simple React code

const App = (props) => {
    const [counter, setCounter] = React.useState(0);
    const isVisible = usePageVisibility();
    const delay = 1000;


    React.useEffect(() => {
        const timeout = setTimeout(() => {
            if (isVisible) {
                setCounter(counter + 1);
            }
        }, delay);

        return () => {
            clearTimeout(timeout);
        };
    });



    return (
        <div>
            <p>Below number gets updated every {delay / 1000} second only if the page is active</p>
            <span id="output">{counter}</span>
        </div>
    );
};

ReactDOM.render(<App />, document.getElementById("root"));
#output{
  font-size: xx-large
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>