Vueのメソッドはリアクティブですか?


9

私はしばらくVueを使用してきましたが、私の経験は常に、基礎となる反応データが更新された場合に再計算する方法でした。私はSOで矛盾する情報に遭遇しました:

  • 私はこの質問に答えようとしていましたが、そうではないと何度も言われました。
  • 受け入れ答えここでは、「あなたが明示的に呼び出したときにのみ評価されます[方法]。」ことを示しています

ドキュメントを検索しましたが、信じられないほど明確なものは何も見つかりませんでした。

それらが反応しない場合、この例はなぜ機能するのですか?

<ul>
  <li v-for="animal in animals" :key="animal.id">
    <span v-if="isAwesome(animal)">{{ animal.name }}</span>
  </li>
</ul>
export default {
  data() {
    return {
      awesomeAnimalIds: [],
      animals: [
        { id: 1, name: 'dog' },
        { id: 5, name: 'cat' },
        { id: 9, name: 'fish' },
      ],
    };
  },
  created() {
    setTimeout(() => {
      this.awesomeAnimalIds.push(5);
    }, 1000);
    setTimeout(() => {
      this.awesomeAnimalIds.push(9);
    }, 2000);
  },
  methods: {
    isAwesome(animal) {
      return this.awesomeAnimalIds.includes(animal.id);
    },
  },
};

私はでしょう本当にこのコミュニティが参照できることを決定的と満足な答えを持っているのが好き。


すばらしい質問です。現実を表す「公式」の回答があるかどうかはわかりません。
タイラー

回答:


4

ドキュメントからの変更の追跡方法に基づいて、次のようになります。

Vue反応サイクル図

  1. コンポーネントインスタンス用に特別なウォッチャーが作成され、再レンダリングが必要になるタイミングが決定されます。

  2. Vueはのすべてのプロパティdataをゲッターとセッターに変換します。

get animals() {
  // Add dependency: potentially trigger a re-render if animals updates
  ...
}
set animals() {
  // Notify the watcher that animals has been updated
  ...
}
get awesomeAnimalIds() {
  // Add dependency: potentially trigger a re-render if awesomeAnimalIds updates
  ...
}
set awesomeAnimalIds() {
  // Notify the watcher that awesomeAnimalIds has been updated
  ...
}
  1. テンプレートがレンダリングされます。レンダリング中に、isAwesomeテンプレートからが呼び出されます。
  2. の本体でisAwesome、getter for awesomeAnimalIdsが呼び出されます。
  3. ウォッチャーはのawesomeAnimalIdsフィールドへの依存関係を確立しdataます。
  4. タイムアウト後、awesomeAnimalIds更新され、awesomeAnimalIdssetter が呼び出されます。
  5. テンプレートはdata通知を受け取ったフィールドに依存するため、再レンダリングがトリガーされます。
  6. 手順(3)を繰り返します。

これと上記のこの例から、次のことを結論付けることができます。

テンプレートから行わdataれたメソッド呼び出しは、メソッド呼び出しスタックで使用されるフィールドのサブセットに対する反応依存を確立します。基本フィールドが更新されると、コンポーネントの再レンダリングがトリガーされます。

テンプレートから呼び出された場合、メソッドは「一度だけ呼び出される」または「起動して忘れる」と誤解されがちです。メソッドは事後依存を確立できるため、これは必ずしも常に当てはまるわけではありません。

では、計算されたプロパティとメソッドのどちらを使用すればよいですか?

計算キャッシュとメソッドのガイドセクションをご覧ください。これが私の見解です。

  • 計算されたプロパティは、リアクティブな依存関係が変更されたときにのみ再評価されます。つまり、効率を高めるためにキャッシングを使用します。
  • 計算されたプロパティには副作用がありません。たとえば、あなたはfetch彼らから電話をかけるべきではありません。
  • 効率上の理由から、可能であれば、常にメソッドよりも計算されたプロパティを優先してください。
  • 副作用がある場合、または引数を渡す必要がある場合は、メソッドを使用します(元の質問に見られるように)。

すてきな明確な説明、ありがとう。
Ackroydd

4

いいえ、メソッドは反応しません。Vueでリアクティブにできるのはデータのみです。

しかし、それはVueがどのように機能するかを理解することが重要です...

  1. Vueはテンプレートを受け取り、それをレンダー関数にコンパイルしてレンダー関数を実行します
  2. レンダリング機能の実行中、Vueはすべてのdata()メンバーを監視します(これは、最初のレンダリング中だけでなく、常にこれを実行します)。レンダリング中にいずれかのデータにアクセスすると、Vueは、このデータメンバーのコンテンツがレンダリングの結果に影響を与えることを認識します。
  3. Vueは、ステップ2で収集された知識を使用します。レンダリングの変更中にデータメンバーが「触れられた」ときはいつでも、再レンダリングが発生し、処理を実行する必要があることを認識しています...

それはあなたが、直接データメンバを参照するには、それを使用している場合は問題ではないcomputedか、でmethodレンダリング中にデータが「タッチ」された場合、データの変更により将来的に再レン​​ダリングがトリガーされます...


1

これは非常に興味深いケースです。

私が読んだことと私の経験から、私は次のことを言えるでしょう。いいえ、方法は本質的に反応的ではありません。メソッドを実行するには、メソッドを明示的に呼び出す必要があります。

しかし、どうすればあなたのケースを説明できますか?私はあなたのコードをサンドボックスに入れました。確かに、IDを配列にプッシュすると、テンプレートが更新されて動物の名前が表示されます。これは反応性を示します。何ができますか?

さて、私は実験を行いました。div生成時に乱数を生成する単純なループを各ループに追加しました。

<li v-for="animal in animals" :key="animal.id">
        <div>{{ random() }}</div>
        <span v-if="isAwesome(animal)">{{ animal.name }}</span>
</li>

...

random() {
      return Math.random();
}

そして、私が見たのは、新しいIDが配列にプッシュされるたびに、すべての乱数が変化するということでした。これは、メソッドisAwesomeがリアクティブであるかのように「見える」理由を理解するための鍵です。

どういうわけか、新しいIDが配列にプッシュされると、Vueはループを完全に再レンダリングし、メソッドを再度実行します。なぜvueがループ全体を再レンダリングするのかについての内部の仕組みを説明することはできません。

だからあなたの質問に答えます。isAwesomeは反応的ではなく、ループの再レンダリングによって作成された幻想にすぎません。


1
これは、コンポーネント内の監視可能なプロパティ(プロップ/データ/計算済み)に当てはまります。彼らはそれのトリガーに変更している時はいつでもupdate発生しre-render、テンプレートにバインドされている任意の方法をトリガ
Ohgodwhy
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.