reactjs 使用useEffect时事件侦听器回调仍然重复

sqserrrh  于 2023-10-17  发布在  React
关注(0)|答案(1)|浏览(151)

我对React、useEffect和向事件侦听器添加回调函数感到困惑。这些侦听器被注册到Google Publisher Tag事件,我试图获得结果,在那里我可以使用传递的参数(在我的示例代码中为display)和回调函数中的事件对象。

<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<script src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"></script>````
const { useEffect } = React;

const slotOnloadCallback = (display, event) => {
    const { slot } = event;
    console.log(`callback called for slot ${slot.getSlotElementId()} - display: ${display}`);
  };

const create = (id, display) => {
  window.googletag = window.googletag || {cmd: []};
  window.googletag.cmd.push(function() {
    const slot = window.googletag.defineSlot('/1234567/example', [728, 90], id);
    slot.addService(googletag.pubads());
    window.googletag.pubads().enableSingleRequest();
    window.googletag.enableServices();
  });

  window.googletag.pubads().addEventListener("slotOnload", slotOnloadCallback.bind(null, display));

  window.googletag.cmd.push(function() {
    window.googletag.display(id);
  });
}

const Ad = (props) => {
  const { id, display } = props;
  console.log(`Ad ${id}: Rendering`);
  useEffect(() => {
    console.log(`Ad ${id}: Mounted`);
    create(id, display)
  }, []);
  return (
    <div id={id}></div>
  );
};

function App() {
  return (
    <div>
      <Ad 
        id="slot-1"
        display="full"
      />
      <p>...</p>
      <Ad
        id="slot-2"
        display="partial"
      />
    </div>
  )
}

ReactDOM.render(<App />, document.querySelector("#app"));

事件侦听器正在工作,但当我将所需的变量绑定到回调时,回调最终会被触发多次(* 呈现的Ad组件的数量)。我想我理解将变量绑定到一个函数使其唯一,因此可以多次注册到一个侦听器,但我认为使用useEffect绕过了这个问题。:(
我得到输出:

"Ad slot-1: Rendering"
"Ad slot-2: Rendering"
"Ad slot-1: Mounted"
"Ad slot-2: Mounted"
"callback called for slot slot-1 - display: full"
"callback called for slot slot-1 - display: partial"
"callback called for slot slot-2 - display: full"
"callback called for slot slot-2 - display: partial"

.其中我很困惑slot-1是如何接收partial的。
有没有一种方法可以确保事件侦听器只在每个组件中触发一次?我尝试过将回调定义移到组件的useEffect块中,也尝试过在App中定义它并将其作为prop传递给组件,但这些都有相同的结果。
任何帮助将非常感谢!

8ehkhllq

8ehkhllq1#

useEffect在开发模式下运行两次。你得注意移除监听器

const create = (id, display) => {
  window.googletag = window.googletag || {cmd: []};
  window.googletag.cmd.push(function() {
    const slot = window.googletag.defineSlot('/1234567/example', [728, 90], id);
    slot.addService(googletag.pubads());
    window.googletag.pubads().enableSingleRequest();
    window.googletag.enableServices();
  });

  const ads = window.googletag.pubads()
  const fn = slotOnloadCallback.bind(null, display)
  ads.addEventListener("slotOnload", fn);

  window.googletag.cmd.push(function() {
    window.googletag.display(id);
  });

  return () => {
    ads.removeEventListener("slotOnload", fn);
  }
}

const Ad = (props) => {
  const { id, display } = props;
  console.log(`Ad ${id}: Rendering`);
  useEffect(() => {
    console.log(`Ad ${id}: Mounted`);
    return create(id, display)
  }, []);
  return (
    <div id={id}></div>
  );
};

相关问题