LoginSignup
1
0

LWCのコールバック関数の指定方法でハマった話

Last updated at Posted at 2024-04-18

目次

  • 概要
  • 何にハマったのか?
  • 原因
  • 解決方法
  • 結論

概要

  • LWCでプラットフォームイベントを受信して、あれこれしたくなったため、リファレンスを眺めながら実装した。リファレンスに記載されたサンプルコードを入力したのにうまくいかなかった。その後、色々試して解決できたので本記事で記録を残しておこうと思った。

何にハマったのか?

結論

subscribe関数への引数で渡すコールバック関数内で、グローバル変数を参照しようとした際にundefinedにってしまう、、、

経緯踏まえて説明します

  • サンプルコードの記載があるリファレンス
  • 上記リファレンスから抜粋したコードに独自にコメントを追加(コメント以外はリファレンスのままです)
    // プラットフォームイベント登録メソッド
    handleSubscribe() {
        // プラットフォームイベント受信時にコールされるCallback関数
        const messageCallback = function (response) {
            console.log('New message received: ', JSON.stringify(response));
            // Response contains the payload of the new message received
        };

        // プラットフォームイベントのサブスク登録メソッド
        subscribe(this.channelName, -1, messageCallback).then((response) => {
            // Response contains the subscription information on subscribe call
            console.log(
                'Subscription request sent to: ',
                JSON.stringify(response.channel)
            );
            this.subscription = response;
            this.toggleSubscribeButton(true);
        });
    }
  • 上記のコードって、一見して何も問題なさそうに見えて、結構簡単に動かせるんだなぁと思い、コードを貼り付けてデプロイしました
  • 実際にプラットフォームイベントを受信することができ、コールバック関数がコールされることを確認しました
  • よしよし、では実際のロジックを書いていこうと思いました
  • その中でコールバック関数内でグローバル変数で定義している値(this.xxxxで参照する値)を参照しようとした時、なぜかグローバル変数の値がundefinedになっていました

原因

strictModeでコールバック関数に、アロー関数以外を渡す場合(functionで定義した関数)はthisの参照先がundefined になってしまうため

    // プラットフォームイベント登録メソッド
    handleSubscribe() {
        // プラットフォームイベント受信時にコールされるCallback関数
        const messageCallback = function (response) {
            console.log('New message received: ', JSON.stringify(response));
            // Response contains the payload of the new message received
+           console.log(this.xxxx) // <=参照できない。undefinedになる。他では参照できるのに
        };

        // プラットフォームイベントのサブスク登録メソッド
        subscribe(this.channelName, -1, messageCallback).then((response) => {
            // Response contains the subscription information on subscribe call
            console.log(
                'Subscription request sent to: ',
                JSON.stringify(response.channel)
            );
            this.subscription = response;
            this.toggleSubscribeButton(true);
        });
    }

情報を整理していきます。

  • jsにはstrict modeというモードがある(MDN
  • 通常strict modeを有効化する場合、 下記のように定義する(上記MDNから抜粋)
    // スクリプト全体の厳格モード構文
    "use strict";
    const v = "こんにちは!厳格モードのスクリプト!";
    
  • strict modeが有効なときは、関数がstrict モードで実行コンテキストに入るときに this 値を明示的に設定しないと、 undefined になる(つまりbindする必要がある。ただしアロー関数は、ソースコード上のコンテキストの this の値が設定される)
  • LWCってどうなっているんだろうって調べたら、LWCは暗黙的(use strictの宣言なし)にstrict modeが有効になっているとリファレンスにちゃんとかいてあった。

解決方法

  • 上記事実をもとにサンプルコードを見ると、thisの参照先がundefinedになることが理解できた
  • どうすればよかったかコードを記載します
    • 方法1(thisをbindする)

          // プラットフォームイベント登録メソッド
          handleSubscribe() {
              // プラットフォームイベント受信時にコールされるCallback関数
              const messageCallback = function (response) {
                  console.log('New message received: ', JSON.stringify(response));
                  // Response contains the payload of the new message received
      +            console.log(this.xxxx) // <=参照できる
              };
      
              // プラットフォームイベントのサブスク登録メソッド
      +        subscribe(this.channelName, -1, messageCallback.bind(this)).then((response) => {
                  // Response contains the subscription information on subscribe call
                  console.log(
                      'Subscription request sent to: ',
                      JSON.stringify(response.channel)
                  );
                  this.subscription = response;
                  this.toggleSubscribeButton(true);
              });
          }
      
      • 方法2(コールバック関数をアロー関数で定義する)
          // プラットフォームイベント登録メソッド
          handleSubscribe() {
              // プラットフォームイベント受信時にコールされるCallback関数
      +          const messageCallback = (response) => {
                  console.log('New message received: ', JSON.stringify(response));
                  // Response contains the payload of the new message received
      +            console.log(this.xxxx) // <=参照できる
              };
      
              // プラットフォームイベントのサブスク登録メソッド
              subscribe(this.channelName, -1, messageCallback).then((response) => {
                  // Response contains the subscription information on subscribe call
                  console.log(
                      'Subscription request sent to: ',
                      JSON.stringify(response.channel)
                  );
                  this.subscription = response;
                  this.toggleSubscribeButton(true);
              });
          }
      

結論

  • リファレンスはしっかり読みましょう
  • 1個のリファレンスだけを信用するのではなく、関連するリファレンスも読み、照らし合わせて情報を整理しましょう
  • 機械は嘘つかない

色々学べました。この記事が誰かのためになれば幸いです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0