Heim > Artikel > Web-Frontend > Vue3-Originalwert-Antwortlösung und wie das Problem des Antwortverlusts gelöst werden kann
ref soll das Problem lösen, dass der Proxy den ursprünglichen Wert nicht direkt vertreten kann. Schauen wir uns zunächst die Verwendung von ref an:
const name = ref('小黑子')
Wie wird ref implementiert? Tatsächlich geht es darum, den ursprünglichen Wert mit einem Objekt zu „verpacken“. Werfen wir einen Blick auf die Implementierung von ref:
function ref(val){ // 使用对象包裹原始值 const wrapper = { value:val } // 利用 reactive 将对象变成响应式数据 return reactive(wrapper) }
ref So einfach ist die Implementierung.
ref führt hauptsächlich diese beiden Dinge als Reaktion auf den ursprünglichen Wert aus:
1 Verwenden Sie ein Objekt, um den ursprünglichen Wert zu umschließen.
2. Verwenden Sie reaktiv, um das Paketobjekt in reaktionsfähige Daten umzuwandeln.
Wir verwenden ref, um ein responsives Objekt zu erstellen, aber wie unterscheiden wir, ob ein Objekt ein normales Objekt oder ein Ref-Objekt ist? So erscheint unsere isref.
Werfen wir einen Blick auf die Verwendung:
const name = ref('cj') console.log(isRef(name)); // true
Was ist also das Implementierungsprinzip? Die Hauptimplementierung befindet sich immer noch in der Ref-API. Werfen wir einen Blick auf den spezifischen Implementierungscode:
function ref(val){ const wrapper = { value:val } Object.defineProperty(warpper,'__v_isRef',{ value:true }) return reactive(wrapper) }
Es stellt sich heraus, dass sie dem Paketobjekt innerhalb von Ref ein nicht aufzählbares und nicht beschreibbares Attribut hinzufügt, und der Wert ist wahr . Auf diese Weise können wir das Attribut überprüfen, um festzustellen, ob es sich um eine Referenz handelt.
function isRef(val) { return val.__v_isRef ?? false }
Was ist Reaktionsverlust? Antwortverlust bedeutet, dass auf die Antwortdaten nicht reagiert wird. Schauen wir uns den folgenden Code an:
const obj = reactive({foo:1,bar:2}) const {foo,bar} = obj obj.foo++ // foo不会改变,还是 1
Das obige obj hat seine Antwort verloren, daher wird kein erneutes Rendern ausgelöst. Warum passiert das? Tatsächlich wird der Erweiterungsoperator aufgrund der Verwendung der Strukturzuweisung diese auch ungültig machen.
const obj = reactive({foo:1,bar:2}) const newObj = {...obj} obj.foo++ // newObj.foo不会改变,还是 1
Dies entspricht der Neudefinition neuer Daten, die nicht mehr die ursprünglichen Antwortdaten sind und natürlich keine Reaktionsfähigkeiten aufweisen.
toRef soll das Problem des Antwortverlusts lösen. Werfen wir einen Blick auf die Implementierung:
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 }
Übergeben Sie zwei Parameter, der erste sind Antwortdaten und der zweite ist ein Schlüssel von obj.
Der erste Teil besteht darin, ein Objekt festzulegen und zu deklarieren. Beim Zugriff auf den toRef-Wert wird der Attributwert zurückgegeben, der den eingehenden Antwortdaten entspricht Wenn der toRef-Wert festgelegt wird, wird der neue Wertesatz verwendet, um den Attributwert entsprechend den Antwortdaten zu aktualisieren. Mit anderen Worten: Das von toRef zurückgegebene Objekt sind immer noch die verwendeten Reaktionsdaten.
Der zweite Teil wird verwendet, um die zurückgegebenen Daten als Referenzdaten festzulegen. Da die von toRef zurückgegebenen Daten den Referenzdaten ähneln, werden sie aus Gründen der Vereinheitlichung direkt als Referenzdaten betrachtet.
Der dritte Teil besteht darin, das deklarierte Attributobjekt zurückzugeben, das den Antwortdaten entspricht.
Auf diese Weise löst toRef das Problem des Antwortverlusts.
toRefs wird das gesamte responsive Objekt dekonstruiert und responsiv gemacht. Der Implementierungscode lautet wie folgt:
function toRefs() { const ret = {} for (const key in obj) { ret[key] = toRef(obj,key) } return ret }
Verwenden Sie eine for-Schleife, um Attribute einzeln zu konvertieren. Werfen wir nun einen Blick auf die Verwendung:
const obj = reactive({foo:1,bar:2}) const {foo,bar} = toRefs(obj) obj.foo++ // foo.value变为2了
Wenn das Attribut ein nicht ursprünglicher Wert ist, kann es nach der Dekonstruktion immer noch reagieren
const obj = reactive({foo:{age:18},bar:2}) const {foo,bar} = obj obj.foo.age++ // foo.age变为2了 obj.bar++ // bar没有改变,还是1
Warum ist das so? Der Grund ist eigentlich ganz einfach, denn dem nicht ursprünglichen Wert wird eine Referenzadresse zugewiesen, was bedeutet, dass die destrukturierte Variable tatsächlich immer noch auf das Attribut der ursprünglichen Antwortdaten verweist. Der ursprüngliche Wert ist eine einfache Zuweisung und reagiert nicht.
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} 了
Was ist der Grund dafür? Die reaktive Neuzuweisungsantwort geht verloren, das heißt, ein neues Objekt wird neu zugewiesen, und es wird auf natürliche Weise zu gewöhnlichen Daten und reagiert nicht mehr. Und ref kann immer noch antworten, da ref intern festgelegt ist. Der Code lautet wie folgt:
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) }
Wir wissen, dass ref tatsächlich bestimmt, ob der in set festgelegte neue Wert ein nicht ursprünglicher Wert ist, und wenn ja, ruft er reactive auf, um ihn in reaktionsfähige Daten umzuwandeln.
Wenn wir ref-responsive Daten verwenden, werden wir immer das Gefühl haben, dass .value erforderlich ist, um den Wert zu erhalten, was die mentale Belastung des Benutzers erhöht.
Ist es möglich, direkt auf den Wert zuzugreifen, anstatt .value zu verwenden?
Bei dieser Verwendung müssen Sie sich keine Gedanken darüber machen, ob es sich bei bestimmten Daten um Referenzdaten handelt oder ob Sie den Wert über das Wertattribut erhalten müssen.
Hier kommt unser Unref ins Spiel. unref implementiert die Möglichkeit, Referenzen automatisch zu entfernen. Wenn das gelesene Attribut eine Referenz ist, wird der der Referenz entsprechende Wert des Attributs direkt zurückgegeben.
Werfen wir einen Blick auf die Implementierung von 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) } }) }
Wir haben festgestellt, dass unref intern Proxy verwendet, um das Zielobjekt zu vertreten, ein Objekt als Parameter empfängt und das Proxy-Objekt des Objekts zurückgibt. Wenn wir auf Unref-Daten zugreifen, wird der Get-Catcher ausgelöst, und dann bestimmt der Catcher intern, ob das eingehende Objekt ein Ref-Objekt ist, und wenn ja, gibt er direkt den .value-Wert von ref zurück. Wenn nicht, wird das Proxy-Objekt direkt zurückgegeben.
Wenn der Wert des von unref zurückgegebenen Proxy-Objekts festgelegt wird, wird der Set-Capturer ausgelöst. Wenn das Proxy-Objekt ref ist, wird der neue Wert, der festgelegt werden muss, .value zugewiesen. Wenn nicht, wird der Zuweisungsprozess direkt ausgeführt .
Nachdem wir ref verwendet haben, um reaktionsfähige Daten zu erstellen und in der Vorlage anzuzeigen, warum nicht .value verwenden?
{{ name }}
其实原因很简单,在组件 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 的能力。
Das obige ist der detaillierte Inhalt vonVue3-Originalwert-Antwortlösung und wie das Problem des Antwortverlusts gelöst werden kann. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!