ジャンボモナカ

34歳のハゲデブがHTML5ハイブリッドアプリ開発プラットフォームmonacaを始めました。

Google AdSenseをReactに対応させる

Reactで作ったwebページに対してGoogle AdSenseを表示させる機会があり、その際に少し手こずったので、対応方法について書く。

まず前提条件として、下記のscriptをheadタグ内に設定しておく。

<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>

Reactを使わなければinsタグとscriptタグを設定することで表示させることができる。

<ins class="adsbygoogle"
    data-ad-client="ca-pub-XXX"
    data-ad-slot="XXX"
></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>

まずはじめにReactのrenderメソッドにすべて入れてみた。

class GoogleAdsense extends React.Component {
    constructor(props) {
      super(props);
    }

    render(){
        return (
            <ins class="adsbygoogle"
                data-ad-client="ca-pub-XXX"
                data-ad-slot="XXX"
            ></ins>
            <script>
            (adsbygoogle = window.adsbygoogle || []).push({});
            </script>
        );
    }
}

単純にrenderメソッドの中に全部入れただけでは、正常に表示させることはできなかった。

そこで、scriptの部分をcomponentDidUpdateメソッドに移動させた。

class GoogleAdsense extends React.Component {
    constructor(props) {
      super(props);
    }

    componentDidUpdate(prevProps, prevState, snapshot){
      window.adsbygoogle = window.adsbygoogle || [];
      window.adsbygoogle.push({});
    }

    render(){
        return (
            <ins class="adsbygoogle"
                data-ad-client="ca-pub-XXX"
                data-ad-slot="XXX"
            ></ins>
        );
    }
}

componentDidUpdateメソッドの中に移動させることによって、updateされる度にgoogle adsenseのjsが呼び出されればいいなぁ〜と淡い期待で組んだところエラーが発生。

adsbygoogle.push() error: All ins elements in the DOM with class=adsbygoogle already have ads in them.

調査してみると、一度、adsbygoogleのpushメソッドをコールした場合、再度、呼び出してしまうとエラーになってしまうようだ。

そこで、一回だけ実行すればいいことがわかったので、componentDidMountメソッドに移動させた。

class GoogleAdsense extends React.Component {
    constructor(props) {
      super(props);
    }

    componentDidMount(){
      window.adsbygoogle = window.adsbygoogle || [];
      window.adsbygoogle.push({});
    }

    render(){
        return (
            <ins class="adsbygoogle"
                data-ad-client="ca-pub-XXX"
                data-ad-slot="XXX"
            ></ins>
        );
    }
}

無事に表示させることができた。

adsbygoogle.pushメソッドを何回も呼び出すとエラーになってしまうのは知らないと気がつかないので、今度から実装する時は意識したい。

CSSの素敵なレイアウトチェック

dev.to

このCSSの組み方によるレイアウトチェックは非常に便利なので、記事が消されても使えるように引用する。


* { background-color: rgba(255,0,0,.2); }
* * { background-color: rgba(0,255,0,.2); }
* * * { background-color: rgba(0,0,255,.2); }
* * * * { background-color: rgba(255,0,255,.2); }
* * * * * { background-color: rgba(0,255,255,.2); }
* * * * * * { background-color: rgba(255,255,0,.2); }
* * * * * * * { background-color: rgba(255,0,0,.2); }
* * * * * * * * { background-color: rgba(0,255,0,.2); }
* * * * * * * * * { background-color: rgba(0,0,255,.2); }

Javaに関する記事も書いています

昔、少しだけJavaを触っていたこともありプライベートではJavaを書いているのですが、色々と忘れてしまっている部分もあり、Javaに関するブログも書いています。

javatar.hatenablog.com

徐々に内容も増やしていく予定なのでJavaにご興味のある方は、是非、ご登録ください。

Reactでコンポーネントが更新された際にDOMの更新をかけたい

Reactでpropsに変更があった際にDOMの更新も行いたい。

例えば、親からもらったpropsに変更があった時、ajaxでリクエストをかけてその結果をもとにDOMの更新を行いたい場合など。

そんなことに直面した場合は、componentDidUpdateメソッドを使えば解決するようだ。

class Hoge extends React.Component {
  constructor(props) {
    this.state = {
      hoge:1
    }
  }
  render(){
    <Foo value={this.state.hoge}></Foo>
  }
}

class Foo extends React.Component {
  constructor(props) {
    this.state = {
      bar: 'hello'
    }
  }

  //Hogeコンポーネントのhogeに変更があった場合に呼ばれる
  componentDidMount(prevProps, prevState, snapshot) {
    if(prevProps.hoge !== this.props.hoge){
      this.setState({
        bar: 'Good Bye'
      });
    }
  }

  render(){
    <div>{this.props.hoge}<br>{this.state.bar}</div>
  }
}

propsに変更があった際にDOMに更新かけたい場合にこのやり方を覚えておきたい。

styleプロパティーでCSSの情報が取得できない件

外部ファイルに定義されているCSSの情報はどうやらstyleプロパティーで取得することはできないようだ。

#hoge {
  height: 44px;
}
//""がリターンされる。本来であれば44pxをリターンしてほしい
console.log(document.querySelector('#hoge').style.height)

そこでこの問題に対してどうするかというと、windowオブジェクトのgetComputedStyleメソッドを使って取得する

var _hoge = document.querySelector('#hoge');
var _height = window.getComputedStyle(_hoge).getPropertyValue('height');
console.log(_height)

どうしてこんなややこしい方法になってしまったのだろうか?

なぜgetComputedStyleメソッドがwindowオブジェクトに紐ついているのか、domに紐つけた方が使いやすくないかなぁ〜っと思ってしまうのだが。

// このパターンはエラーなのだが、こっちの方が直感的に理解しやすいと思うんですけど、自分だけかな?
var _height = document.querySelector('#hoge').getPropertyValue('height');
// エラー
console.log(_height)

ReactでinnerHTMLを実行したい

React.Componentのrenderメソッドでhtmlを描画する時に、htmlが含まれている場合は、エスケープされてしまう。

class Hoge extends React.Component {
  constructor(props) {
    super(props);
  }

  render(){
    //fooにhtmlが含まれていてもエスケープされてしまう
    return <span>{foo}</span>
  }
}

そこでエスケープされずにinnerHTMLのようにhtmlとして実行して欲しい場合は、dangerouslySetInnerHTML属性を使って描画することができるようだ。

class Hoge extends React.Component {
  constructor(props) {
    super(props);
  }

  render(){
    let createMarkup = function(){
      return {__html: '<span>foo</span>'};
    }
    //fooにhtmlが含まれていてもエスケープされてしまう
    return <span dangerouslySetInnerHTML={createMarkup()}></span>
  }
}

確かにhtmlとして認識してくれたが、dangerouslySetInnerHTML属性ってまたどっ直球すぎてすごい名前だな。

TypeScript Property 'value' does not exist on type 'Element'

TypeScriptでvalueプロパティーに値を設定したコードにコンパイルエラーが発生していた。

エラー内容は、 「hoge.ts:176:30 - error TS2339: Property 'value' does not exist on type 'Element'.」 というものだった。

コードはごくごく簡単なdomを選択してvalueプロパティに値を設定するというもの。

document.querySelector('._foo').value = "bar";

調べてみるとキャストを行う必要があり、HTMLInputElementにしたら問題が解決した。

(<HTMLInputElement>document.querySelector('._foo')).value = "bar";

正直にカミングアウトすると、毎回、こうするの結構、めんどくさい。