この記事はVueのライフサイクルを理解するのに役立ちます

この記事はVueのライフサイクルを理解するのに役立ちます

序文:

Vueインスタンスは、作成前に一連の初期化プロセスを経ます。たとえば、データ監視を設定し、テンプレートをコンパイルし、インスタンスを DOM にマウントし、データが変更されたときにDOMを更新する必要があります。同時に、ライフサイクル フックと呼ばれるいくつかの関数もこのプロセス中に実行され、ユーザーは特定のシナリオで独自のコードを追加できるようになります。

ソース コード内で最終的にライフサイクルを実行する関数はすべて、 src/core/instance/lifecycleで定義されているcallHookメソッドを呼び出します。

関数 callHook (vm: コンポーネント、フック: 文字列) をエクスポートします。
 // #7573 ライフサイクルフックを呼び出すときに依存関係コレクションを無効にする
  プッシュターゲット()
  const ハンドラ = vm.$options[フック]
  if (ハンドラ) {
    (i = 0、j = handlers.length; i < j; i++) の場合 {
      試す {
        ハンドラ[i].call(vm)
      } キャッチ (e) {
        handleError(e, vm, `${hook} フック`)
      }
    }
  }
  (vm._hasHookEvent)の場合{
    vm.$emit('フック:' + フック)
  }
  ポップターゲット()
}


callHook関数のロジックは非常にシンプルです。渡された文字列 hook に従って、 vm.$options[hook]に対応するコールバック関数配列を取得し、それを走査して実行します。実行時には、関数実行のコンテキストとして vm が使用されます。

1. beforeCreate & created

Vue がインスタンス化されるとき、 beforeCreate関数とcreated関数の両方が _init メソッドで実行されます。これはsrc/core/instance/init.jsで定義されています。

Vue.prototype._init = 関数 (オプション?: オブジェクト) {
  // ...
  ライフサイクルの初期化(vm)
  イベントの初期化(vm)
  レンダリングの初期化(vm)
  フックを呼び出します(vm、'beforeCreate')
  initInjections(vm) // データ/プロパティの前にインジェクションを解決する
  初期化状態(vm)
  initProvide(vm) // data/props の後に provide を解決する
  callHook(vm, '作成済み')
  // ...
}


beforeCreatecreatedのフック呼び出しがinitState前後にあることがわかります。 initStateの機能は、 propsdatamethodswatchcomputedなどのプロパティを初期化することです。これらについては後で詳しく分析します。当然ですが、 beforeCreateフック関数はpropsdataで定義された値を取得することはできず、 methodsで定義された関数を呼び出すこともできません。

これら 2 つのフック関数が実行されると、DOM はレンダリングされないため、DOM にアクセスできません。一般的に、コンポーネントがロード時にバックエンドと対話する必要がある場合は、これら 2 つのフック関数で実行できます。 propsdataなどのデータにアクセスする必要がある場合は、 createdフック関数を使用する必要があります。後でvue-routerと vuex を紹介するときに、両方でbeforeCreatdフック関数が混在していることがわかります。

2. マウント前とマウント済み

名前が示すように、 beforeMountフック関数はmountで、つまり DOM がマウントされる前に実行されます。これは、 src/core/instance/lifecycle.jsで定義されているmountComponent関数で呼び出されます。

エクスポート関数mountComponent(
  vm: コンポーネント、
  el: ?要素、
  水分補給?: ブール値
): 成分 {
  vm.$el = el
  // ...
  callHook(vm, 'beforeMount')
 
  コンポーネントを更新します
  /* イスタンブールは無視します */
  process.env.NODE_ENV !== 'production' && config.performance && mark の場合 {
    更新コンポーネント = () => {
      定数名 = vm._name
      定数 id = vm._uid
      const startTag = `vue-perf-start:${id}`
      const endTag = `vue-perf-end:${id}`
 
      マーク(開始タグ)
      定数 vnode = vm._render()
      マーク(終了タグ)
      measure(`vue ${name} render`, startTag, endTag)
 
      マーク(開始タグ)
      vm._update(vnode、ハイドレーション)
      マーク(終了タグ)
      measure(`vue ${name} patch`, startTag, endTag)
    }
  } それ以外 {
    更新コンポーネント = () => {
      vm._update(vm._render(), ハイドレーション)
    }
  }
 
  // ウォッチャーのコンストラクタ内でこれを vm._watcher に設定します
  // ウォッチャーの初期パッチは$forceUpdateを呼び出す可能性があるので(例えば、子プロセス内で)、
  // コンポーネントのマウントされたフック)、これはvm._watcherが既に定義されていることに依存します
  新しいウォッチャー(vm、updateComponent、noop、{
    前に () {
      (vm._isMounted) の場合 {
        callHook(vm, 'beforeUpdate')
      }
    }
  }, true /* isRenderWatcher */)
  水分補給 = 偽
 
  // 手動でマウントされたインスタンス、自身にマウントされた呼び出し
  // マウントは、挿入されたフック内のレンダリングによって作成された子コンポーネントに対して呼び出されます
  (vm.$vnode == null)の場合{
    vm._isMounted = true
    callHook(vm, 'マウント済み')
  }
  戻り値
}


vm. render()関数を実行して VNode をレンダリングする前に、 beforeMountフック関数が実行されますvm. update() VNode patch後、 moutedフックが実行されます。注意すべきは、 moutedフック関数の実行には判断ロジックがあるということです。vm vm.$vnodeが null の場合、これはコンポーネントの初期化プロセスではなく、外部のnew Vueを介した初期化プロセスであることを意味します。では、コンポーネントはいつmountedのでしょうか?

コンポーネントのVNode patch後、 invokeInsertHook関数が実行され、 insertedVnodeQueueに保存されたフック関数が 1 つずつ実行されます。これはsrc/core/vdom/patch.jsで定義されています。

関数invokeInsertHook(vnode、キュー、初期値){
 // コンポーネントルートノードの挿入フックを遅延し、
  // 要素が実際に挿入されます
  if (isTrue(initial) && isDef(vnode.parent)) {
    vnode.parent.data.pendingInsert = キュー
  } それ以外 {
    (i = 0; i < キューの長さ; ++i) の場合 {
      キュー[i].data.hook.insert(キュー[i])
    }
  }
}


この関数はinsertフック関数を実行します。コンポーネントの場合、挿入フック関数はsrc/core/vdom/create-component.jscomponentVNodeHooksで定義されています。

定数componentVNodeHooks = {
  // ...
  挿入 (vnode: MountedComponentVNode) {
    const { コンテキスト、コンポーネントインスタンス } = vnode
    コンポーネントインスタンスがマウントされている場合
      コンポーネントインスタンス._isMounted = true
      callHook(componentInstance, 'マウント済み')
    }
    // ...
  },
}


このフック関数では、各子コンポーネントがmoutedフック関数を実行していることがわかります。また、 insertedVnodeQueue追加する順序は、最初に子、次に親であることが以前に分析されているため、同期的にレンダリングされる子コンポーネントの場合、 mountedフック関数の実行順序も最初に子、次に親になります。

3. beforeUpdate と updated

名前が示すように、 beforeUpdateupdatedフック関数の実行タイミングは、データが更新されたときである必要があります。これまで、 Vueのデータ双方向バインディングと更新を分析していませんでした。次の章でこの処理を詳しく紹介します。

beforeUpdateの実行時間は、 Watcherのレンダリングのbefore関数内にあります。

エクスポート関数mountComponent(
  vm: コンポーネント、
  el: ?要素、
  水分補給?: ブール値
): 成分 {
  // ...
 
  // ウォッチャーのコンストラクタ内でこれを vm._watcher に設定します
  // ウォッチャーの初期パッチは$forceUpdateを呼び出す可能性があるので(例えば、子プロセス内で)、
  // コンポーネントのマウントされたフック)、これはvm._watcherが既に定義されていることに依存します
  新しいウォッチャー(vm、updateComponent、noop、{
    前に () {
      (vm._isMounted) の場合 {
        callHook(vm, 'beforeUpdate')
      }
    }
  }, true /* isRenderWatcher */)
  // ...
}


ここで判断が行われることに注意してください。つまり、このフック関数はコンポーネントがmountedれた後にのみ呼び出されます。

updateの実行時間は、 src/core/observer/scheduler.jsで定義されているflushSchedulerQueue関数が呼び出されたときです。

関数flushSchedulerQueue() {
  // ...
  // 更新されたキューを取得する
  更新されたフックを呼び出します(更新されたキュー)
}
 
関数callUpdatedHooks(キュー){
  i = キューの長さとする
  (i--) {
    const ウォッチャー = キュー[i]
    定数 vm = ウォッチャー.vm
    (vm._watcher === ウォッチャー && vm._isMounted) の場合 {
      callHook(vm, '更新')
    }
  }
}


flushSchedulerQueue関数については後ほど詳しく説明しますが、まずは概要を理解しておいてください。updatedQueue は更新されたwathcerの配列です。callUpdatedHooks 関数では、これらの配列を走査します。 updated updatedQueue callUpdatedHooksは、現在のwatchervm._watcherであり、コンポーネントがmountedている場合にのみ実行されます。

前にも述べたように、コンポーネントのmountプロセス中に、レンダリングWatcherがインスタンス化され、VM 上のデータの変更を監視して再レンダリングします。このロジックはmountComponent関数が実行されたときに発生します。

エクスポート関数mountComponent(
  vm: コンポーネント、
  el: ?要素、
  水分補給?: ブール値
): 成分 {
  // ...
  // これは省略形です let updateComponent = () => {
      vm._update(vm._render(), ハイドレーション)
  }
  新しいウォッチャー(vm、updateComponent、noop、{
    前に () {
      (vm._isMounted) の場合 {
        callHook(vm, 'beforeUpdate')
      }
    }
  }, true /* isRenderWatcher */)
  // ...
}


次に、 Watcherをインスタンス化するプロセスで、 isRenderWatcherそのコンストラクターで判断され、現在のwatcherインスタンスがsrc/core/observer/watcher.jsで定義されているvm._watcherに割り当てられます。

デフォルトクラスWatcherをエクスポートします{
  // ...
  コンストラクタ(
    vm: コンポーネント、
    expOrFn: 文字列 | 関数、
    cb: 機能、
    オプション?: ?オブジェクト、
    isRenderWatcher?: ブール値
  ){
    this.vm = vm
    if (isRenderWatcher) {
      vm._watcher = これ
    }
    vm._watchers.push(これ)
    // ...
  }
}


同時に、現在のwathcerインスタンスがvm. watchersにプッシュされますvm. watcher 、vm 上のデータの変更を監視して再レンダリングするために特に使用されるため、レンダリング関連のwatcherです。そのため、 callUpdatedHooks関数では、 vm._watcherのコールバックが実行された後にのみ、 updatedフック関数が実行されます。

4. beforeDestroyとdestroy

名前が示すように、 beforeDestroy およびdestroyedフック関数,beforeDestroyコンポーネントの破壊の段階です。コンポーネントの破壊プロセスについては後で詳しく説明しますが、最後に $ destroyメソッドが呼び出されます。これはsrc/core/instance/lifecycle.jsで定義されています。

Vue.prototype.$destroy = 関数 () {
    const vm:コンポーネント = this
    (vm._isBeingDestroyed)の場合{
      戻る
    }
    callHook(vm, 'beforeDestroy')
    vm._isBeingDestroyed = true
    // 親から自分自身を削除する
    定数親 = vm.$parent
    if (親 && !parent._isBeingDestroyed && !vm.$options.abstract) {
      削除(親.$children, vm)
    }
    // ティアダウンウォッチャー
    (vm._watcher)の場合{
      vm._watcher.ティアダウン()
    }
    i = vm._watchers.length とします。
    (i--) {
      vm._watchers[i].ティアダウン()
    }
    // データオブジェクトから参照を削除する
    // 凍結されたオブジェクトにはオブザーバーがない可能性があります。
    (vm._data.__ob__)の場合{
      vm._data.__ob__.vmCount--
    }
    // 最後のフックを呼び出します...
    vm._isDestroyed = 真
    // 現在レンダリングされているツリーの破棄フックを呼び出す
    vm.__patch__(vm._vnode、null)
    // 火で破壊されたフック
    callHook(vm, '破棄されました')
    // すべてのインスタンス リスナーをオフにします。
    vm.$オフ()
    // __vue__ 参照を削除
    (vm.$el)の場合{
      vm.$el.__vue__ = null
    }
    // 循環参照を解除する (#6759)
    (vm.$vnode) の場合 {
      vm.$vnode.parent = null
    }
  }


beforeDestroyフック関数は、 destroy関数実行の最初に実行され、 parentchildrenからの自身の削除、 watcherの削除、現在レンダリングされているVNodeの破棄フック関数の実行など、一連の破棄アクションを実行します。実行が完了すると、 destroyフック関数が再度呼び出されます。

$destroy の実行中に、 vm. patch (vm._vnode, null)が実行され、その子コンポーネントの破棄フック関数がトリガーされます。そのため、再帰呼び出しはレイヤーごとに行われ、 destroyフック関数の実行順序は、マウントされたプロセスと同じように、最初に子、次に親の順になります。

5. 有効化と無効化

activated およびdeactivatedフック関数はkeep-aliveコンポーネント用に特別にカスタマイズされたフックです。keep keep-aliveコンポーネントの紹介時に詳しく紹介しますので、ここでは保留にしておきます。

要約:

このセクションでは、主に Vue ライフサイクルにおける各フック関数の実行タイミングと順序を紹介します。分析により、 createdフック関数でデータにアクセスし、 mountedフック関数で DOM にアクセスし、 destroyフック関数でタイマーによる破棄作業を実行できることがわかります。これらを理解することで、適切なライフサイクルでさまざまなことを行うことができます。

Vue のライフサイクルを理解するためのこの記事はこれで終わりです。Vue のライフサイクルに関するその他のコンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Vueライフサイクルの違いの詳細な説明
  • Vue.js の計算プロパティ、監視プロパティ、ライフサイクルの詳細な説明
  • Vue フィルター、ライフサイクル関数、vue-resource の簡単な紹介
  • Vueライフサイクルの詳細な理解
  • Vueコンポーネントライフサイクルの動作原理の分析
  • Vueライフサイクルを有効にすると、データ操作を再要求せずに前のページに戻ります。
  • Vue のプロパティ、メソッド、ライフサイクルのサンプルコードの詳細な説明
  • Vueライフサイクル操作の例
  • Vuex を Vue ライフサイクルに注入するプロセスについての簡単な説明
  • Vue ライフサイクルの調査
  • Vue js のライフサイクル(読めばわかります)(推奨)
  • Vue ライフサイクルとフック関数の簡単な例

<<:  MySQL 使用仕様の概要

>>:  Dockerを使用して完全な開発環境を構築するための詳細なチュートリアル

推薦する

...

Javascript サンプル プロジェクトでの虫眼鏡効果の実装プロセス

目次序文事例: JD.com の虫眼鏡効果の模倣オフセットシリーズクライアントシリーズスクロールシリ...

Linux サーバーに Java Web プロジェクトをデプロイするための完全なチュートリアル

この記事は主にインターネット上の他のチュートリアルを参考にしています。実際に操作した上でのまとめです...

Dockerでのpython3.8イメージのインストールについて

Docker Hub公式サイト1. Pythonミラーを検索するdocker 検索 python 2...

mysql 行列変換サンプルコード

1. 需要3 つのテーブルがあります。一定期間にわたるさまざまな抗生物質感受性の結果、つまり rep...

vuex データの永続化のための 2 つの実装ソリューション

目次ビジネス要件:解決策 1: vuex-persistedstate解決策2: vuex-pers...

MySQLデッドロックの原因と解決策

データベースは、オペレーティング システムと同様に、複数のユーザーが使用する共有リソースです。複数の...

Vue が Web オンラインチャット機能を実現

この記事では、Webオンラインチャットを実装するためのVueの具体的なコードを参考までに紹介します。...

React Hooksの詳細な説明

目次フックとは何ですか?クラスコンポーネント機能コンポーネントフックが作られた理由要約するフックとは...

React でカレンダー コンポーネントを構築するためのステップ バイ ステップ ガイド

目次事業背景テクノロジーの活用技術的な問題デザインのアイデア😱 困惑と苦痛に満ちた顔🙄考え始める🌲デ...

MySQLで最新のトランザクションIDを照会する方法

前に書いた内容: ビジネス ロジックの判断を行うために、最新のトランザクション ID を表示する必要...

入力と画像を揃えるためにvertical-alignを使用します

input と img を同じ行に配置すると、img タグが常に input より 1 つ上になり、...

0.1秒の価値!フロントエンドのウェブページの高速化の問題について簡単に説明します

私が現在の仕事の面接を受けたとき、リーダーが真剣にこう言っていたのを覚えています。「今の世の中はイン...

nginx rewriteを使用してURLをリダイレクトする方法

最近仕事でnginxの設定を変更する必要が頻繁にあり、nginxでrewriteを使用する方法を学び...

Mac Docker x509証明書の問題を解決する

質問最近、プライベートミラーセンターにログインする必要がありましたが、ログイン時にエラーメッセージが...