ホームページ  >  記事  >  ウェブフロントエンド  >  vue3 独自の値応答ソリューションと応答損失の問題の解決方法

vue3 独自の値応答ソリューションと応答損失の問題の解決方法

PHPz
PHPz転載
2023-05-12 15:52:062912ブラウズ

    1. ref

    ref の導入は、プロキシが元の値を直接プロキシできないという問題を解決することです。まず ref の使用方法を見てみましょう:

    const name = ref('小黑子')

    ref はどのように実装されますか?実際には、元の値をオブジェクトで「ラップ」することです。 ref の実装を見てみましょう。

    function ref(val){
        // 使用对象包裹原始值
        const wrapper = {
            value:val    
        }
        // 利用 reactive 将对象变成响应式数据
        return reactive(wrapper)
    }

    ref の実装は非常に簡単です。

    ref は、元の値に応じて主に次の 2 つのことを行います:

    • 1. オブジェクトを使用して元の値をラップします。

    • 2. reactive を使用して、ラップされたオブジェクトを応答性の高いデータに変換します。

    2. isref の実装

    応答オブジェクトを作成するために ref を使用しますが、オブジェクトが通常のオブジェクトであるか ref オブジェクトであるかをどのように区別するのでしょうか?したがって、isref が表示されます。

    その使用法を見てみましょう:

    const name = ref('cj') console.log(isRef(name)); // true

    それでは、その実装原理は何でしょうか?メインの実装はまだ ref API 内にあります。具体的な実装コードを見てみましょう:

    function ref(val){
        const wrapper = {
            value:val    
        }
        Object.defineProperty(warpper,'__v_isRef',{
            value:true    
        })
        return reactive(wrapper)
    }

    列挙不可および書き込み不可の属性が ref 内のパッケージ オブジェクトに追加されていることがわかります。値は true です。このようにして、属性をチェックしてそれが参照であるかどうかを判断できます。

    function isRef(val) {
        return val.__v_isRef ?? false
    }

    3. 応答損失

    応答損失とは何ですか?応答喪失とは、応答データが応答しないことを意味します。以下のコードを見てみましょう:

    const obj = reactive({foo:1,bar:2})
    const {foo,bar} = obj
    obj.foo++    // foo不会改变,还是 1

    上記の obj は応答を失ったため、再レンダリングはトリガーされません。なぜそうなるのでしょうか?実際、構造割り当てを使用しているため、展開演算子もそれを無効にします。

    const obj = reactive({foo:1,bar:2})
    const newObj = {...obj}
    obj.foo++   // newObj.foo不会改变,还是 1

    これは、元の応答データではなくなった新しいデータを再定義することに相当し、当然のことながら応答機能はありません。

    1. toRef の登場

    toRef は応答損失の問題を解決するためのものです。その実装を見てみましょう:

    function toRef(obj,key) {
        const wrapper = {
            get value() {
                return obj[key]        
            },
            set value(val) {
                obj[key] = val
            }    
        }
        Object.defineProperty(wrapper,'__v_isRef',{
            value:true    
        })
        return wrapper
    }

    2 つのパラメータを渡します。1 つ目は応答データ、2 つ目は obj のキーです。

    • 最初の部分は、オブジェクトを設定して宣言することです。オブジェクトは最初に get value 属性を設定します。toRef 値にアクセスすると、受信応答データに対応する属性値は次のようになります。返された後、 value 属性を持つセットを使用して toRef 値を設定し、セットの新しい値を取得して、応答データに対応する属性値を更新します。言い換えれば、toRef によって返されるオブジェクトは依然として使用される応答データです。

    • 2 番目の部分は、返されたデータを参照データに設定するために使用されます。 toRef が返すデータは ref データと類似しているため、統一のためにそのまま ref データとして扱います。

    • #3 番目の部分は、応答データに対応して宣言された属性オブジェクトを返すことです。

    この方法で、toRef は応答損失の問題を解決します。

    2. toRefs

    toRefs を追加すると、応答性のあるオブジェクト全体が分解され、応答性が高くなります。実装コードは次のとおりです。

    function toRefs() {
        const ret = {}
        for (const key in obj) {
            ret[key] = toRef(obj,key)    
        }
        return ret
    }

    for ループを使用して属性を 1 つずつ変換します。次に、使用法を見てみましょう:

    const obj = reactive({foo:1,bar:2})
    const {foo,bar} = toRefs(obj)
    obj.foo++    // foo.value变为2了

    3. その他の奇妙な応答性喪失状況

    属性が元の値ではない場合、分解後も応答できる可能性があります

    const obj = reactive({foo:{age:18},bar:2})
    const {foo,bar} = obj
    obj.foo.age++    // foo.age变为2了
    obj.bar++       // bar没有改变,还是1
    # ##何故ですか?その理由は実際には非常に単純で、元ではない値には参照アドレスが割り当てられているためです。これは、構造化された変数が実際には依然として元の応答データの属性を指していることを意味します。元の値は単純な代入であるため、応答しません。

    reactive 响应数据重新赋值后不再响应,ref 响应数据赋值后依然响应
    let obj1 = reactive({foo:1,bar:2})
    let obj2 = ref({foo:1,bar:2})
     
    // 假如 obj1 与 obj2 直接展示在页面上
    obj1 = {boo:2,far:3}    // 页面 obj1 还是 {foo:1,bar:2}
    obj2.value = {boo:2,far:3}    // 页面 obj2 变为 {boo:2,far:3} 了

    その理由は何ですか?リアクティブな再割り当て応答が失われる、つまり新しいオブジェクトが再割り当てされると、当然通常のデータになり応答しなくなります。また、ref は内部で設定されているため、引き続き応答できます。コードは次のとおりです。

    function ref(val){
        const wrapper = {
            value:val
            set value(val) {    // isObject 这里代表判断是否是非原始值的一个方法
                 value = isObject(val) === 'Object' ? reactive(val) : val       
            }
        }
        Object.defineProperty(warpper,'__v_isRef',{
            value:true    
        })
        return reactive(wrapper)
    }

    実際、 ref は set に設定された新しい値がオリジナルでない値であるかどうかを判断し、そうである場合は reactive を呼び出して応答性の高いデータに変換することがわかります。

    4. Unref は ref を自動的に削除します

    ref 応答型データを使用する場合、値を取得するために .value が必要であると常に感じ、ユーザーの精神的負担が増加します。

    .value を使用する代わりに値に直接アクセスすることは可能ですか?

    このように、特定のデータが参照データであるかどうか、または value 属性を通じて値を取得する必要があるかどうかを気にする必要はありません。

    ここで unref が登場します。 unref は、ref を自動的に削除する機能を実装します。自動 ref 削除とは、読み取られた属性が ref である場合、その ref に対応する value 属性値が直接返されることを意味します。

    unref の実装を見てみましょう:

    function unref(target) {
        return new Proxy(target,{
            get(target,key,receiver) {
                const value = Reflect.get(target,key,receiver)
                return value.__v_isRef ? value.value : value        
            },
            set(target,key,newValue,receiver) {
                const value = target[key]
                if (value.__v_isRef) {
                    value.value = newValue
                    return true            
                }        
                return Reflect.set(target,key,newValue,receiver)
            }
        })
    }

    unref は内部で Proxy を使用してターゲット オブジェクトをプロキシし、オブジェクトをパラメータとして受け取り、そのプロキシ オブジェクトを返すことがわかりました。物体。 unref データにアクセスすると、get catcher がトリガーされ、受信したオブジェクトが ref オブジェクトであるかどうかを内部で判断し、そうであれば ref の .value 値が直接返されます。そうでない場合は、プロキシ オブジェクトが直接返されます。

    unref によって返されたプロキシ オブジェクトの値を設定するとき、set Capturer がトリガーされます。プロキシ オブジェクトが ref の場合、設定する必要のある新しい値が .value に割り当てられます。そうでない場合、割り当ては処理は直接実行されます。

    知識の拡張

    ref を使用してレスポンシブ データを作成し、テンプレートに表示した後、.value を使用しないのはなぜでしょうか。

    
     
    

    其实原因很简单,在组件 setup 中声明的 ref 响应式数据会传递给 unref 函数进行处理。所以在模板中访问 ref 的值,无需通过 value 属性来访问。

    我们使用的 reactive 其实也是有 自动脱 ref 功能的,看一下下方例子:

    const count = ref(0)
    const obj = reactive({conut})
     
    obj.count    // 0

    我们可以看见 obj.count 是一个 ref 响应式数据。在 count 外层包裹一层对象,再传递给 reactive 后,再访问 obj.count 时就不需要再通过 value 属性访问值了。

    也正是因为 reactive 内部也同样实现了自动脱 ref 的能力。

    以上がvue3 独自の値応答ソリューションと応答損失の問題の解決方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。