Vue3リスナーの実装原理は何ですか

王林
リリース: 2023-05-16 15:04:06
転載
1424 人が閲覧しました

レスポンシブ オブジェクトのリッスン

先ほど、計算プロパティについて説明しました。これは、レスポンシブ データの値を自動的に計算し、キャッシュすることができます。また、応答データが変更されたときにいくつかのプリセット操作を実行するだけでよい場合は、watch リスナーを使用できます。最初に最も単純な例を実装してから、少しずつ拡張してみましょう。

const data = {foo: 1}
const obj = reactive(data)
watch(obj, () => {
  console.log('obj已改变')
})
ログイン後にコピー

この例では、

watch リスナーを使用します。obj のプロパティが変更されると、コンソールには obj が出力されます。変更されました。計算されたプロパティの以前の実装に基づいて、ここではすでに一般的なアイデアが得られています。 watch を応答オブジェクトの副作用関数と考えると、応答オブジェクトが変更されると、副作用関数の実行がトリガーされます。

副作用関数をトリガーしたい場合は、まず副作用関数を収集する必要があります。副作用関数がどのように収集されたか覚えていますか?はい、

リアクティブデータが get の場合、副作用関数 が収集されます。したがって、まず、リアクティブ オブジェクトによって収集される watch を作成する必要があります。

function watch(getter, cb) {
  effect(
    () => getter.foo
  )
}
ログイン後にコピー

次に、デフォルトのメソッドを実行させる必要もあります。応答データが

set の場合、副作用関数がトリガーされます。ここでトリガーしたいのは、cb で渡されるコールバック関数です。ここでは、計算されたプロパティを実装するときにスケジューラーを使用できます。スケジューラーが存在する場合、settrigger# をトリガーします## は最初にスケジューラ内の関数を実行します。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;">function watch(getter, cb) { effect( () =&gt; getter.foo, { scheduler() { cb() } } ) }</pre><div class="contentsignin">ログイン後にコピー</div></div>

Vue3リスナーの実装原理は何ですかシンプルなリスナーが完成しました。ここでは、簡単にするために関数を完全に記述し、

obj.foo

のリッスンのみをサポートします。次に、応答オブジェクトのプロパティをリッスンする方法を考えなければなりません。 前の考え方によると、応答オブジェクトの属性をリッスンしたい場合は、オブジェクトの各属性に

get

する必要があります。これには、オブジェクトが走査されます。再帰的に。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;">function traverse(value, seen = new Set()) { // (1) if(typeof value !== &amp;#39;object&amp;#39; || value === null || seen.has(value)) return seen.add(value) for(const key in value) { traverse(value[key], seen) } return value }</pre><div class="contentsignin">ログイン後にコピー</div></div>オブジェクトを再帰的に走査するときに循環参照によって引き起こされる無限ループを回避するために、

(1)

Set を作成しました。同じオブジェクトが繰り返し出現する場合、直接戻ります。 プロパティ値のリッスン

Vue3 では、応答オブジェクトのプロパティ値を直接リッスンすることはできません。応答オブジェクトのプロパティ値をリッスンする必要がある場合は、応答オブジェクトによってリスナーを収集できるように

getter

関数が必要です。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;">const data = { foo: 1 } const obj = reactive(data) watch( () =&gt; obj.foo, () =&gt; { console.log(&amp;#39;obj.foo已改变&amp;#39;) })</pre><div class="contentsignin">ログイン後にコピー</div></div>属性を指定すると、現在のリスナーは指定された属性によってのみトリガーされ、応答オブジェクト全体を再帰的に走査する必要がなくなります。

function watch(getter, cb) {
  if(typeof getter !== &#39;function&#39;) getter = traverse(getter) // (2)
  effect(
    () => getter(),
    {
      scheduler() {
        cb()
      }
    }
  )
}
ログイン後にコピー

Vue3リスナーの実装原理は何ですか(2) で判定を追加しました。受信関数がすでに

getter

関数である場合は、それを直接使用します。そうでない場合はgetter 関数は応答オブジェクトとみなされ、再帰的に走査する必要があります。 リッスンして新しい値と古い値を取得する

Vue では、コールバック関数

cb で応答性の高いデータ更新の前後に新しい値を取得できる必要もあります。 ()

は古い値になります。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;">const data = { foo: 1 } const obj = reactive(data) watch( () =&gt; obj.foo, (newValue, oldValue) =&gt; { console.log(newValue, oldValue) })</pre><div class="contentsignin">ログイン後にコピー</div></div>次の質問は、

newValue

oldValue を取得する方法です。 newValue は簡単に解決できます。コールバック関数 cb() を実行すると、得られるのは newValue ですが、oldValue の値を取得する方法は次のとおりです。 ### ここ? watch から古い値を取得するには、副作用関数をすぐに実行することはできません。ここで何が思い浮かびますか?はい、計算プロパティを実装するときに、副作用関数の自動実行を禁止できる lazy を使用しました。

function watch(getter, cb) {
  if(typeof getter !== &#39;function&#39;) getter = traverse(getter)
  let oldValue
  const effectFn = effect(
    () => getter(),
    {
      lazy: true, // (3)
      scheduler() {
          cb(oldValue)
      }
    }
  )
  oldValue = effectFn() // (4)
}
ログイン後にコピー
(3) で lazy

スイッチを設定し、

lazy を設定すると副作用関数の実行権限が自分に渡されます。 (4)では副作用関数を手動で実行します。ここで振り返る必要があります。前に渡した getter は関数 () => obj.foo であり、関数 effect の 1 つのパラメーターは次のとおりです。実際に実行される副作用関数なので、手動で実行するのは実際には関数 () => obj.foo なので、古い値が取得されます。 新しい値を取得するにはどうすればよいですか?応答データの値が更新された後、副作用関数 effect

がトリガーされて実行されます。scheduler 属性が存在する場合、スケジューラが実行されます。スケジューラでは、副作用関数を再度実行し、

() => obj.foo を通じて変更された新しい値を取得できます。

function watch(getter, cb) {
  if(typeof getter !== &#39;function&#39;) getter = traverse(getter)
  let oldValue, newValue
  const effectFn = effect(
    () => getter(),
    {
      lazy: true,
      scheduler() {
        newValue = effectFn()
        cb(newValue, oldValue)
        oldValue = newValue // (5)
      }
    }
  )
  oldValue = effectFn()
}
ログイン後にコピー
(5) では、コールバック関数 cb()

を実行した後、後処理を行い、次のコールバックの準備のために

oldValue の値を更新しました。 。

#コールバック関数が作成されたときに、リスナーがすぐにそれを実行するようにしたい場合もあります。 Vue3リスナーの実装原理は何ですか

const data = {
  foo: 1
}
const obj = reactive(data)
watch(
  () => obj.foo, 
  (newValue, oldValue) => {
      console.log(&#39;newValue:&#39;, newValue,&#39;, oldValue:&#39;, oldValue)
  },
  { immediate: true }
)
ログイン後にコピー

immediate

の値が

true の場合、すぐに実行する必要があります。要件を明確にした後、watch リスナーを改善しましょう。

function watch(getter, cb, options = {}) {
  if(typeof getter !== &#39;function&#39;) getter = traverse(getter)
  let oldValue, newValue
  function job() { // (6)
    newValue = effectFn()
    cb(newValue, oldValue)
    oldValue = newValue
  }

  const effectFn = effect(
    () => getter(),
    {
      lazy: true,
      scheduler: job,
    }
  )

  if(options.immediate) {  // (7)
    job()
  } else {
    oldValue = effectFn()
  } 
}
ログイン後にコピー

在(6)处,我们抽离了回调函数的执行逻辑,当options.immediate存在时,直接触发执行。

Vue3リスナーの実装原理は何ですか

实现效果

Vue3リスナーの実装原理は何ですか

以上がVue3リスナーの実装原理は何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:yisu.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート