WeChatウィジェットコンポーネントのライフサイクルのステップ記録


コンポーネントライフサイクルは、通常、私たちのビジネスロジックの始まりです。
業務シーンが複雑であれば、部品のライフサイクルが予期されていない表現がある場合、
いくつかの怪しい業務のバグを引き起こすかもしれません。それらは再現と修復が非常に難しいです。
コンポーネントatachedライフサイクル実行回数
通常の理解によれば、moved/show/hideなどのライフサイクルは複数回実行される可能性があるほか、
厳密には、コンポーネントローディングに関連するライフサイクル、例えば、created、atached、readyなど、各コンポーネントのインスタンスは一回だけ実行されるべきである。しかし事実は本当にこのようですか?
背景
この問題の発見は、私たちが小プログラムのエラーログで、
Canot redefine property:isComponentのような大量のエラーがありました。

原因分析
変数名によってコードの定義にさかのぼることができます。

Component({
 lifetimes: {
 attached() {
 Object.defineProperty(this, 'isComponent', {
 enumerable: true,
 get() { return true },
 });
 },
 },
});
このようなエラーの原因は、オブジェクトに設定不可能な属性を再定義しようとすることにあり、
具体的にはMDN上の説明を見ることができる。
しかし、この定義はatachedライフサイクルの中に書いてあります。もしかして、コンポーネントのatachedライフサイクルは二回トリガされましたか?
あら、そんなはずないです。
はい、とても不思議です。
シーンの復元
この問題は簡単には再現できませんでしたが、簡単に削除したり、剥いたりして、最終的には問題の根源を見つけました。
ページonLoadの前に、set Dataを通して状態を変えてサブアセンブリをレンダリングさせると、サブアセンブリのtachedライフサイクルが2回トリガされます。

このシーンは、以下のコードで再現するか、または直接にプログラムコードセグメントにアクセスすることができます。
ページ

// page.js
Page({
 data: {
 showChild2: false,
 },
 onChild1Attached() {
 this.setData({ showChild2: true });
 },
});


<!-- page.wxml -->
<child1 bind:attached="onChild1Attached"></child1>
<child2 wx:if="{{ showChild2 }}"></child2>
サブコンポーネント1
ページと一緒にレンダリングし、atachedの時に、triggerEventを通じて、ページの更新状態を通知し、サブアセンブリ2をレンダリングする。

// child1.js
Component({
 lifetimes: {
 attached() {
 this.triggerEvent('attached');
 },
 },
});


<!-- child1.wxml -->
<view>child1</view>
サブコンポーネント2
ライフサイクルを2回実行したので、エラーが発生しました。

// child2.js
Component({
 lifetimes: {
 attached() {
 Object.defineProperty(this, 'isComponent', {
 enumerable: true,
 get() { return true },
 });
 },
 },
});

<!-- child2.wxml -->
<view>child2</view>
コンポーネントreadyライフサイクルの実行タイミング
ウィジェットの公式文書では、コンポーネントのライフサイクルの実行手順が明確にされていませんが、ログを印刷することで簡単に確認できます。
  • ローディング段階では、順次実行されます。created->atached->ready
  • はアンインストール段階で順次実行されます。
    ですから、この順番はcreated->atached->ready->detachedのように見えます。
    しかし、実際の状況は本当ですか?
    背景
    時間があります。カスタマーサービスはよくフィードバックします。私たちのプログラムにはシリアルデータの現象があります。
    例えば、A商店の生放送はB商店の商品を展示しています。
    原因分析
    シリアルデータは複数のシーンで発生していますが、データはメッセージを通じてウィジェットに送られたものと考えられ、最終的にはWebSocket通信に問題があると疑われます。
    マイクロプログラムでは、WebSocket通信コンポーネントを実装しました。コアロジックは以下の通りです。
    
    // socket.js
    Component({
     lifetimes: {
     ready() {
     this.getSocketConfig().then(config => {
     this.ws = wx.connectSocket(config);
     this.ws.onMessage(msg => {
     const data = JSON.parse(msg.data);
     this.onReceiveMessage(data);
     });
     });
     },
     detached() {
     this.ws && this.ws.close({});
     },
     },
     methods: {
     getSocketConfig() {
     //        socket     
     return new Promise(() => {});
     },
     onReceiveMessage(data) {
     event.emit('message', data);
     },
     },
    });
    
    簡単に言えば、コンポーネントreadyの時に、WebSocket接続を初期化して、メッセージのプッシュを待ち受けて、Detached段階で接続をオフにするということです。
    問題がないように見えますが、結果から逆にするしかないです。
    データがシリアルされています。WebSocketメッセージがシリアルされています。Websocketは正常に閉じられていません。
    シーンの復元
    ここの実際の業務ロジックは複雑ですので、簡単なコードでしか検証できません。
    継続的な試験によって、最終的に発見された:
    コンポーネントのreadyとdetachedの実行順序は明確な順序関係がない。

    このシーンは、以下のコードで再現されてもよく、またはプログラムコードセグメントに直接アクセスされてもよい。
    ページ
    
    // page.js
    Page({
     data: {
     showChild: true,
     },
     onLoad() {
     this.setData({ showChild: false });
     },
    });
    
    
    
    <!-- page.wxml -->
    <child wx:if="{{ showChild }}" />
    
    コンポーネント
    コンポーネントがreadyされていないときは、コンポーネントを廃棄し、先に同期してdetachedを実行し、その後、非同期でreadyを実行します。
    
    // child.js
    Component({
     lifetimes: {
     created() {
     console.log('created');
     },
     attached() {
     console.log('attached');
     },
     ready() {
     console.log('ready');
     },
     detached() {
     console.log('detached');
     }
     },
    });
    
    広く開拓する
    初期化されたジョブをreadyからatachedの段階に前置きしても、非同期の動作がある限り、detachedが非同期のコールバックより先に実行される場合がある。
    したがって、コンポーネントdetached段階での廃棄操作を完全に信頼しないでください。
    締め括りをつける
    ここでは、WeChatウィジェットのライフサイクルについての記事を紹介します。これに関連して、より多くの関連小プログラムコンポーネントのライフサイクルの内容を紹介します。私達の以前の文章を検索したり、次の関連記事を見たりしてください。これからもよろしくお願いします。