浏览代码

:bug: Fixes issue with setters accessing deeply nested data (#4265)

Eric Kwoka 1 年之前
父节点
当前提交
541cb8ef8f
共有 2 个文件被更改,包括 50 次插入1 次删除
  1. 2 1
      packages/alpinejs/src/scope.js
  2. 48 0
      tests/cypress/integration/scope.spec.js

+ 2 - 1
packages/alpinejs/src/scope.js

@@ -72,7 +72,8 @@ let mergeProxyTrap = {
             ) || objects[objects.length - 1];
         const descriptor = Object.getOwnPropertyDescriptor(target, name);
         if (descriptor?.set && descriptor?.get)
-            return Reflect.set(target, name, value, thisProxy);
+            // Can't use Reflect.set here due to [upstream bug](https://github.com/vuejs/core/blob/31abdc8adad569d83b476c340e678c4daa901545/packages/reactivity/src/baseHandlers.ts#L148) in @vue/reactivity
+            return descriptor.set.call(thisProxy, value) || true;
         return Reflect.set(target, name, value);
     },
 }

+ 48 - 0
tests/cypress/integration/scope.spec.js

@@ -109,3 +109,51 @@ test(
         get("button").should(haveText("clicked"));
     }
 );
+
+test(
+    "properly merges the datastack with nested data",
+    [
+        html`
+            <div x-data="{ foo: { bar: 'fizz' } }">
+                <div x-data="{ bar: 'buzz' }">
+                    <span
+                        id="1"
+                        x-text="foo.bar + bar"
+                        @click="foo.bar = foo.bar + bar"
+                    ></span>
+                </div>
+                <span id="2" x-text="foo.bar"></span>
+            </div>
+        `,
+    ],
+    ({ get }) => {
+        get("span#1").should(haveText("fizzbuzz"));
+        get("span#2").should(haveText("fizz"));
+        get("span#1").click();
+        get("span#1").should(haveText("fizzbuzzbuzz"));
+        get("span#2").should(haveText("fizzbuzz"));
+    }
+);
+
+test(
+    "handles getter setter pairs of object",
+    [
+        html`
+            <div x-data="{ foo:  { bar: 'fizzbuzz' } }">
+                <div
+                    x-data="{ get bar() { return this.foo.bar }, set bar(value) { this.foo.bar = value } }"
+                >
+                    <span id="one" x-text="bar" @click="bar = 'foobar'"></span>
+                </div>
+                <span id="two" x-text="foo.bar"></span>
+            </div>
+        `,
+    ],
+    ({ get }) => {
+        get("span#one").should(haveText("fizzbuzz"));
+        get("span#two").should(haveText("fizzbuzz"));
+        get("span#one").click();
+        get("span#one").should(haveText("foobar"));
+        get("span#two").should(haveText("foobar"));
+    }
+);