当サイトは、アフィリエイト広告を利用しています

【Gatsby】MutationObserverでAdSense未配信時に非表示にする

作成日:2022月08月06日
更新日:2024年01月27日

このブログにはgoolgeAdsenseで広告をつけているのだが、
よく広告が未取得( data-ad-status="unfilled" )になり謎の空白ができてしまう
時があり、何とか未取得の場合に非表示にできないか調べたところ、
GoogleAdSenseヘルプにMutationObserverを使えとあったので
MutationObserverの動きを簡単に試してみた。

MutationObserverとは?

MutationObserverは監視するDOM要素とコールバック関数を設定すれば
監視してるDOM要素に変更があった場合、コールバック関数を実行できる。

MutationObserverの使い方

基本的な使い方はコールバック関数を引数にしてMutationObserverオブジェクトを作って
オブジェクトに監視対象要素を設定する

MutationObserver
~
//オプション
const options = {
childList: true, //直接の子の変更を監視
characterData: true, //文字の変化を監視
characterDataOldValue: true, //属性の変化前を記録
attributes: true, //属性の変化を監視
subtree: true //全ての子要素を監視
};
// 変更検知時のコールバック関数
const callback = (mutationsList) => {
mutationsList.forEach((element) => {
// 任意の処理
console.log(element);
console.log(element.target.id);
console.log(element.target.className);
});
};
//MutationObserverオブジェクト生成
const obs = new MutationObserver(callback);
//ターゲット要素の監視を開始
//ターゲット要素をuseRefで設定
obs.observe(sampleRef.current, options);
// クリーンアップで監視を停止
return () => obs.disconnect();
}, []);
~

オプション

監視オプションを設定する。
詳しくはMutation observerを参照

変更検知時のコールバック関数

監視対象DOM要素の変更を検知した時に実行される関数。
引数としてDOM に生じた個々の変更を保持したMutationRecordのリストが渡されるので
それを元に処理を行う。
MutationRecordの詳細はMutationRecordを参照。

MutationObserverオブジェクト生成

コールバック関数を引数にしてMutationObserverオブジェクトを生成する。

ターゲット要素の監視を開始

MutationObserverオブジェクトのobserveメソッドに下記を渡して
監視を開始させる。

  • 監視対象DOM要素(DOMノード)
  • オプション

クリーンアップで監視を停止

監視を終了する

サンプル実装

React + EmotionでMutationObserverを使ったサンプルを実装して
動きを確認する。

サンプル実装の仕様

changeColorボタンを押せば色が変わるだけの簡単なサンプル。
このボタンを押したタイミングで監視対象のDOM要素のclassをEmotionで付け替える。

App.jsx
/** @jsxImportSource @emotion/react */
import { css } from "@emotion/react";
import "./styles.css";
import { useState, useEffect, useRef } from "react";
export default function App() {
// DOM要素取得のため
const sampleRef = useRef(null);
const [flg, setFlg] = useState(false);
const handleClick = () => {
setFlg((prevFlg) => !prevFlg);
};
useEffect(() => {
//オプション
const options = {
// childList: true, //直接の子の変更を監視
// characterData: true, //文字の変化を監視
// characterDataOldValue: true, //属性の変化前を記録
attributes: true, //属性の変化を監視
// subtree: true //全ての子要素を監視
};
// 変更検知時のコールバック関数
const callback = (mutationsList) => {
mutationsList.forEach((element) => {
// 任意の処理
console.log(element);
console.log(element.target.id);
console.log(element.target.className);
});
};
//インスタンス化
const obs = new MutationObserver(callback);
//ターゲット要素の監視を開始
//ターゲット要素をuseRefで設定
obs.observe(sampleRef.current, options);
// クリーンアップで監視を停止
return () => obs.disconnect();
}, []);
return (
<div className="App">
<h1 id="1" ref={sampleRef} css={flg ? [style1] : [style2]}>
Hello CodeSandbox
</h1>
<h2>react + emotion</h2>
<h2>MutationObserver</h2>
<button onClick={() => handleClick()}>changeColor</button>
</div>
);
}
const style1 = () => [
css`
color: red;
`
];
const style2 = () => [
css`
color: blue;
`
];
  • MutationObserverのobserveメソッドにはuseRefで取得したDOMノードを設定している。
  • ボタン押下でstateのflgが変えると監視対象要素(h1)のclassが動的に切り替わり、それを
    MutationObserverが検知してcallback関数が実行されログ出力される

動作確認

codesandboxで動作確認する

React MutationObserver

MutationObserverでGoogleAdSenseを非表示にしてみる

実際にMutationObserverを使ってAdSenseがdata-ad-status="unfilled"になり
広告未配信の場合に広告を非表示にするようGoogleAdSense表示用コンポーネントを
編集する

Adsense.jsx
import React, { useEffect, useRef, useState } from 'react';
import { css } from 'twin.macro';
import { isMobile } from 'react-device-detect';
const Adsense = props => {
const { currentPath, type } = props;
const adRef = useRef(null); // 広告要素取得
const [dispFLg, setFlg] = useState(true); // 広告表示不フラグ
useEffect(() => {
if (window) {
// mobileの場合は表示後に読み込む
if (isMobile) {
window.onload = function() {
window.adsbygoogle = window.adsbygoogle || [];
window.adsbygoogle.push({});
};
} else {
window.adsbygoogle = window.adsbygoogle || [];
window.adsbygoogle.push({});
}
}
}, [currentPath]);
// 広告が未配信の場合に非表示にする
useEffect(() => {
// オプション
const options = {
attributes: true, // 属性の変化を監視
attributeFilter: ['data-ad-status'], // 指定した属性を監視
};
// 変更検知時のコールバック関数
const callback = mutationsList => {
mutationsList.forEach(element => {
// 未配信(data-ad-status === "unfilled)の場合
if (element.target.attributes['data-ad-status'].value === 'unfilled') {
setFlg(false);
}
});
};
// インスタンス化
const obs = new MutationObserver(callback);
// ターゲット要素の監視を開始
// ターゲット要素をuseRefで設定
obs.observe(adRef.current, options);
// クリーンアップで監視を停止
return () => obs.disconnect();
}, []);
const adsence = () => {
switch (type) {
case 'display':
return (
// dispFLgがfalseの場合にunfilledでスタイルを設定する
<div css={[dispFLg || unfilled]}>
<ins
ref={adRef}
className="adsbygoogle"
style={{ display: 'block' }}
data-ad-client="ca-pub-xxxxxxxxxxxxxxxx"
data-ad-slot="xxxxxxxxxx"
data-ad-format="auto"
data-full-width-responsive="true"
/>
</div>
);
case 'infeed':
return (
<div css={[dispFLg || unfilled]}>
<ins
ref={adRef}
className="adsbygoogle"
style={{ display: 'block' }}
data-ad-format="fluid"
data-ad-layout-key="xxxxxxxxxx"
data-ad-client="ca-pub-xxxxxxxxxxxxxxxx"
data-ad-slot="xxxxxxxxxx"
/>
</div>
);
case 'mdx':
return (
<div css={[dispFLg || unfilled]}>
<ins
ref={adRef}
className="adsbygoogle"
style={{ display: 'block' }}
data-ad-layout="in-article"
data-ad-format="fluid"
data-ad-client="ca-pub-xxxxxxxxxxxxxxxx"
data-ad-slot="xxxxxxxxxx"
/>
</div>
);
case 'Multiplex_column':
return (
<div css={[dispFLg || unfilled]}>
<ins
ref={adRef}
className="adsbygoogle"
style={{ display: 'block' }}
data-ad-format="autorelaxed"
data-ad-client="ca-pub-xxxxxxxxxxxxxxxx"
data-ad-slot="xxxxxxxxxx"
/>
</div>
);
case 'Multiplex_row':
return (
<div css={[dispFLg || unfilled]}>
<ins
ref={adRef}
css={[dispFLg || unfilled]}
className="adsbygoogle"
style={{ display: 'block' }}
data-ad-format="autorelaxed"
data-ad-client="ca-pub-xxxxxxxxxxxxxxxx"
data-ad-slot="xxxxxxxxxx"
/>
</div>
);
case 'display_sq':
return (
<div css={[dispFLg || unfilled]}>
<ins
ref={adRef}
css={[dispFLg || unfilled]}
className="adsbygoogle"
style={{ display: 'block' }}
data-ad-slot="xxxxxxxxxx"
data-ad-format="auto"
data-full-width-responsive="true"
/>
</div>
);
default:
return (
<div css={[dispFLg || unfilled]}>
<ins
ref={adRef}
css={[dispFLg || unfilled]}
className="adsbygoogle"
style={{ display: 'block' }}
data-ad-client="ca-pub-xxxxxxxxxxxxxxxx"
data-ad-slot="xxxxxxxxxx"
data-ad-format="auto"
data-full-width-responsive="true"
/>
</div>
);
}
};
return <div>{adsence()}</div>;
};
export default Adsense;
// 非表示にする関数(Emotionで指定)
const unfilled = () => [
css`
display: none;
`,
];
  • adsence広告にuseRefをつける
  • 広告非表示用のuseStateをつくる
  • MutationObserverでRefをつけたエレメントの属性を指定して監視する
  • 変更検知時、変更内容がunfilledの場合、useStateをfalseにする
  • useStateがfalseの場合のみEmotionでdisplay:noneのスタイルをつける。

Gatsby製ブログにAdSense広告をつける方法について下記記事でまとめています

まとめ

サンプルを作ってみることでMutationObserverの動きは理解できた。 使い方としては監視領域と監視要素の交差を検知してコールバック関数を実行できる
intersection observer apiと同じような感じでした。
Reactで使う場合はhooksのuseState,useRef,useEffectと併用する必要がありそう。
直接DOMをいじることもできそうだが、React的にはあまりよくなさそうなので...

参考

下記を参考にさせて頂きました。

新着記事

タグ別一覧
top