ホームページ >ウェブフロントエンド >Vue.js >Vue のレスポンシブ データ処理方法の詳細な分析
この記事は、vue を学習し、vue がレスポンシブ データをどのように処理するかについて説明するのに役立ちます。お役に立てれば幸いです!
vue のレスポンシブ データについては多くの疑問があるかもしれません。
たとえば、なぜ代わりにプロキシを使用する必要があるのですか?
たとえば、なぜ 2 つの API (reactive と ref) があるのですか?
たとえば、vue はどのように応答性を実装するのでしょうか?
実際、これらに対する答えはソース コードの中にあります。
最初の記事「vue3 のアップグレードとは」では、プロキシを使用する利点と Object.defineProperty の欠点についても触れました。しかし今日は角度を変えて、chatGPT にこの質問に答えてもらいたいと思います。 [関連する推奨事項: vuejs ビデオ チュートリアル 、Web フロントエンド開発 ]
そうですね、私が要約したものよりも優れていると思います。
# それでは、次の質問に進みます。 この答えはより正式なものに感じられ、私が望む答えは得られません。その理由は実際には非常に簡単で、プロキシ メソッドは値の型をプロキシできず、オブジェクトのみをプロキシできるからです。したがって、値型データを処理するには追加のメソッドが必要です。
もちろん、1 つの ref で世界を征服することもできます。vue のソースコードに互換性があれば、自動的に変換されます。
これを理解した上で、今日のを見てみましょう。 ハイライトは、vue3 のソース コードを模倣し、応答性の高いシステムを実装することです。関連するコードをクリックして表示し、記事のタイトルに従ってさまざまなブランチを選択できます。 reactive の実装
プロキシを使用して、単純なプロキシ関数をリアクティブに実装できます。
function reactive(target) { const isObject = (val) => val !== null && typeof val === 'object' if (!isObject(target)) { console.warn(`数据必须是对象: ${String(target)}`) return target } const proxy = new Proxy(target, { get: (target, key, receiver) => { console.log('get', key) const res = Reflect.get(target, key, receiver) // track(target, key) // 这句很关键,不然嵌套数据,里面的不会响应 if (isObject(res)) { return reactive(res) } return res }, set: (target, key, value, receiver) => { console.log('set', key, value) const result = Reflect.set(target, key, value, receiver) // trigger(target, key, value) return result }, deleteProperty: () => { const result = Reflect.deleteProperty(target, key) return result } }) return proxy } const person = reactive({ name: '', age: 18, like: ['apple'] }) person.name = 'vue test'复制代码注: Reflect
Reflect.get(target, key) は、target[key] に直接アクセスすることとは少し異なります。
プロキシ オブジェクト内で this が指す get、set などがある場合、これをリダイレクトできます。
例:
const person = new Proxy({ name: "vue test", age: 18, get info() { return 'name is :' + this.name + ' age is:' + this.age } }, { get: (target, key, receiver) => { console.log('get', key) // return target[key] return Reflect.get(target, key, receiver) } }) console.log(person.info)复制代码
Reflect を使用すると、名前と年齢にアクセスするときにトリガーできます。
ターゲットに変更した後は、情報内で 1 回だけトリガーされます。
return target[key]复制代码
ref の実装
上記と同様に、最初に関数を宣言し、次に get および set を通じてデータにアクセスします。
function ref(value) { return new RefImpl(value) } class RefImpl { constructor(value) { // 如果值是对象,则用reactive处理 this._value = isObject(value) ? reactive(value) : value // 记录一下初始值 this._rawValue = value } get value() { // trackRefValue(this) return this._value } set value(newVal) { if (!Object.is(newVal, this._rawValue)) { // 更新原始数据 this._rawValue = newVal // 更新 .value 的值 this._value = isObject(newVal) ? reactive(newVal) : value // triggerRefValue(this) } } }复制代码
ソース コードでは、get/set が value を通じて設定されるため、.value で ref を使用する必要がある理由も非常に直感的に説明されています。
依存関係の収集とトリガーを追加する
答えは、コレクションとトリガーに依存することです。つまり、get がトリガーされると、get をトリガーする条件 [関数] を保存します。set がトリガーされると、それを再実行して条件 [関数] をトリガーします。 ]. ]それだけでは十分ではありませんか?
もう一度コードを見て、トラック収集メソッドとターゲット トリガー メソッドを追加します。 (つまり、上記のコード スニペットでコメントアウトされた 2 行のコード)
さらに、トリガー関数を管理するためにエフェクト関数も必要です。
let activeEffect = null const targetMap = new WeakMap() // 依赖收集/触发 function track(target, key) { let depsMap = targetMap.get(target) if (!depsMap) { targetMap.set(target, (depsMap = new Map())) } let dep = depsMap.get(key) if (!dep) { dep = new Set() } dep.add(activeEffect) depsMap.set(key, dep) } function trigger(target, key, value) { const depsMap = targetMap.get(target) if (!depsMap) { return } const deps = depsMap.get(key) if (!deps) { return } deps.forEach(effectFn => { if (effectFn.scheduler) { effectFn.scheduler() } else { effectFn() } }) } function effect(fn,options = {}) { const effectFn = () => { try { activeEffect = effectFn return fn() } catch (error) { activeEffect = null } } if (!options.lazy) { effectFn() } effectFn.scheduler = options.scheduler return effectFn } const person = reactive({ name: "hello world" }) effect(() => { console.log('effect person', person.name) }) setTimeout(() => { person.name = 'setTimeout world' }, 2000)复制代码
activeEffect は、トリガー条件関数を保存するために使用されます。
targetMap は依存関係辞書を格納するために使用されます。形式は次のとおりです
{ target: { key: [] } }复制代码
出力結果は hello world です。2 秒後に依存関係関数が再実行され、setTimeout world が出力されます
概要
effect は非常に重要な関数であり、useEffect や watch など多くの API がこの関数をベースにして開発されています。コンポーネントの更新も後述するエフェクト機能に基づいて行われます。
効果がわからない場合は、実行順序を整理してください。
記事に関連するコードは vue/examples で参照でき、vue の模倣実装バージョンは package/reactivity で参照できます。
(学習ビデオ共有:vuejs 入門チュートリアル
、基本プログラミング ビデオ )
以上がVue のレスポンシブ データ処理方法の詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。