React.js - 仅当页面处于活动状态时才触发“useEffect”

时间:2021-05-14 19:14:02

标签: html css reactjs svg

TL;DR

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


我正在 React 网站上工作,并使用“CSS 转换”创建 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 钩子,但是我们如何使用 React 获得与 $(document).ready() 相同的行为?

以下是 Vanialla-JS 代码

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

  setTimeout(logoDraw, 10)
});

更新:

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

1 个答案:

答案 0 :(得分:1)

在网上搜索了几个小时后,我终于在一篇名为“Harnessing the Page Visibility API with React”的博文中找到了完美的答案。

它做两件事之一:

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

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


如果页面处于活动状态,我们可以使用“Page Visibility 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()
  

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

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

    

  return (
    <div>
      <p>Below number gets updated every 3 seconds 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>