【问题标题】:Why not reactive property are reactive in my template?为什么在我的模板中反应性属性不是反应性的?
【发布时间】:2021-02-27 00:20:04
【问题描述】:

我目前正在使用 Vue.js 3 中引入的新反应性 API。我已按照 documentation 上的说明进行操作,据我了解,当我使用 ref 设置变量时,我将其转换为反应性值。如果我不使用ref,则该变量不是反应性的,如果我更新它,则不应在模板中更新它。

我对我的测试结果感到惊讶:

<script src="https://unpkg.com/vue@next"></script>
<div id="app">
  <my-component></my-component>
</div>
<script>
  const app = Vue.createApp({});
  app.component("my-component", {
    template: `
      <div>
        <ul>
          <li>Data not reactive : {{ countNotReactive }}</li>
          <li>Data reactive : {{ countReactive }}</li>
        </ul>
        <button @click="inc">+1</button>
      </div>
    `,
    setup() {
      const countNotReactive = 1;
      const countReactive = Vue.ref(1);

      return {
        countNotReactive,
        countReactive
      };
    },
    methods: {
      inc() {
        this.countNotReactive++;
        this.countReactive++;
      }
    }
  });
  app.mount("#app");
</script>

当我点击 +1 按钮时,我的模板中的所有计数器都会递增。这是渲染:

<!-- Initial -->
<div>
  <ul>
    <li>Data not reactive : 1</li>
    <li>Data reactive : 1</li>
  </ul>
  <button>+1</button>
</div>

<!-- After click on +1 -->
<div>
  <ul>
    <li>Data not reactive : 2</li>
    <li>Data reactive : 2</li>
  </ul>
  <button>+1</button>
</div>

我的期望是只看到反应计数器增加。有人可以向我解释为什么不是这样吗?

我不明白为什么在这种情况下我应该使用ref。谁能给我一个例子,让我可以看到 ref 和 non-ref 变量之间的区别?

【问题讨论】:

    标签: vue.js vuejs3 vue-reactivity


    【解决方案1】:

    您正在混合使用 Option API 和 Composition API。使用 Option API 的 method 对象和您内部的 inc 方法创建两个变量

    this.countNotReactive
    this.countReactive
    

    这些变量在您的模板中获取并覆盖从您的 Composition API 设置方法返回的变量。

    只是不要将两者混为一谈,而是这样尝试:

    <script src="https://unpkg.com/vue@next"></script>
    <div id="app">
      <my-component></my-component>
    </div>
    <script>
      const app = Vue.createApp({});
      app.component("my-component", {
        template: `
          <div>
            <ul>
              <li>Data not reactive : {{ countNotReactive }}</li>
              <li>Data reactive : {{ countReactive }}</li>
            </ul>
            <button @click="inc">+1</button>
          </div>
        `,
        setup() {
          const countNotReactive = 1;
          const countReactive = Vue.ref(1);
          
          const inc = () => {
            countNotReactive++;
            countReactive.value++;
          }
    
          return {
            inc,
            countNotReactive,
            countReactive
          };
        },
      });
      app.mount("#app");
    </script>
    

    这就是区别所在。 refs 值保存在其 value 属性中,而普通的非反应变量可以直接访问。看这里:https://v3.vuejs.org/api/refs-api.html#ref

    【讨论】:

      【解决方案2】:

      你可以在同一个组件中同时使用组合和选项 api,但你不应该在两个 API 之间共享方法和属性,你的逻辑应该是这样的:

      const {
        createApp
      } = Vue;
      const App = {
      
      
      }
      const app = createApp(App)
      app.component("my-component", {
        template: `
            <div>
              <ul>
                <li>Data not reactive : {{ countNotReactive }}</li>
                <li>Data reactive : {{ countReactive }}</li>
               
              </ul>
              <button @click="inc">+1</button>
           
            </div>
          `,
        setup() {
          const countNotReactive = 1;
          const countReactive = Vue.ref(1);
      
          function inc() {
            countNotReactive++;
            countReactive.value++;
          }
          return {
            inc,
            countNotReactive,
            countReactive
          };
        },
      
      });
      app.mount('#app')
      <script src="https://unpkg.com/vue@3.0.0-rc.11/dist/vue.global.prod.js"></script>
      
      <div id="app">
        Vue 3 app
      
        <my-component></my-component>
      </div>

      实际上,countNotReactive 并没有像 watch hook 中显示的那样改变:

      const {
        createApp
      } = Vue;
      const App = {
      
      
      }
      const app = createApp(App)
      app.component("my-component", {
        template: `
            <div>
              <ul>
                <li>Data not reactive : {{ countNotReactive }}</li>
                <li>Data reactive : {{ countReactive }}</li>
               
              </ul>
              <button @click="inc">+1</button>
           
            </div>
          `,
        setup() {
          const countNotReactive = 1;
          const countReactive = Vue.ref(1);
      
        Vue.watch(countReactive,()=>{
        console.log("countReactive",countReactive.value)
         console.log("countNotReactive",countNotReactive)
        
         })
        
          return {
          
            countNotReactive,
            countReactive
          };
        },
        methods: {
            inc() {
              this.countNotReactive++;
              this.countReactive++;
            }
          }
      });
      app.mount('#app')
      <script src="https://unpkg.com/vue@3.0.0-rc.11/dist/vue.global.prod.js"></script>
      
      <div id="app">
        Vue 3 app
      
        <my-component></my-component>
      </div>

      您得到的行为由以下代码解释:

      const myConst="I'm a constant"
      console.log(myConst)
      let obj={myConst} //adding myConst as property in obj which in our case is the `this` (vue instance)
      
      console.log(obj.myConst)
      obj.myConst="updated value"
      
      console.log(obj.myConst)//this prints the updated value
      
      //but if we try myConst="new value" this raises an error
      
      console.log(myConst)//still the same as we declared
      
      //conclusion : this.myConst is not the same as myConst

      【讨论】:

        猜你喜欢
        • 2018-08-24
        • 2020-09-24
        • 2018-10-12
        • 1970-01-01
        • 2021-03-18
        • 2013-11-14
        • 2016-05-15
        • 2020-05-07
        • 2017-09-30
        相关资源
        最近更新 更多