【问题标题】:Why are computed properties not reactive in my Vue 3 app?为什么计算属性在我的 Vue 3 应用程序中没有反应性?
【发布时间】:2021-03-18 10:45:33
【问题描述】:

问题

Vue 2: 计算属性在 vuex 存储突变后更新。

Vue 3: 计算属性在 vuex 存储突变后更新。

Vuex 4

目的:从 Firestore 获取帖子。添加到“postsArray”。提交突变。

注意:函数“getNextPosts”是从允许无限滚动的(工作)交叉点观察者调用的。

const postsArray: Array<string> = [];
const vuexStore = createStore({
  state: {
    posts: []
  },
  actions: {
    // See https://firebase.google.com/docs/firestore/query-data/query-cursors#paginate_a_query
    getFirstPosts({ commit }) {
      const getFirstPosts = async () => {
        const firstPostsQuery = firestore.collection("posts").limit(3);

        // Get FIRST posts.
        const firstPosts = await firstPostsQuery.get();

        // Add to postsArray.
        for (const doc of firstPosts.docs) {
          postsArray.push(doc.id);
        }

        // Add to vuex store.
        commit("addFirstPostsToVuex", postsArray);

        // Set reference.
        lastPostDownloaded = firstPosts.docs[2]; // 3rd post.
      };
      getFirstPosts();
    },
    getNextPosts({ commit }) {
      const getNextPosts = async () => {
        const nextPostsQuery = firestore
          .collection("posts")
          .startAfter(lastPostDownloaded)
          .limit(2);

        // Get NEXT posts.
        const nextPosts = await nextPostsQuery.get();

        // Add to postsArray.
        for (const doc of nextPosts.docs) {
          postsArray.push(doc.id);
        }

        // Add to vuex store.
        commit("addNextPostsToVuex", postsArray);

        // Update reference.
        lastPostDownloaded = nextPosts.docs[1]; // 2nd post.
      };
      getNextPosts();
    }
  },
  mutations: {
    addFirstPostsToVuex(state, value) {
      state.posts = value;
    },
    addNextPostsToVuex(state, value) {
      state.posts = value;
    }
  }
});

计算属性

export default ({
  computed: {
    posts() {
      // List rendering.
      return vuexStore.state.posts;
    }
  }
});

v-for

<template>
  <div id="feed">
    <article class="post" v-for="post in posts" v-bind:key="post.id">
      <header class="info">
        {{ post }}
      </header>
    </article>
  </div>
</template>

【问题讨论】:

  • 你能分享你使用计算属性的组件的完整代码
  • 另外,您可以在计算属性中使用 ...mapState 来代替导入整个商店
  • 如果你使用 vuex getter 怎么办:vuex.vuejs.org/guide/getters.html
  • 请分享 main.ts 代码
  • 我也很想看到这个问题的适当解决方案/解释,所以我开始了赏金。

标签: firebase vue.js vuex vuejs3 vuex4


【解决方案1】:

新旧版本在 Vuex 内部的状态定义略有不同。

**In Vuex3 state was just a prop with an Object while in Vuex4 it has return an Object or a function which returns an Object.**

从 V3 迁移到 V4 时,您一开始可能不会注意到其中的区别,因为 V3 风格也适用于 V4。当您拥有模块并拥有它们的多个实例时,差异就会显示出来。那么状态必须是一个函数,它返回一个对象以避免状态污染(由 tony19 评论)。

模块:

// Vuex 3.x Module
const moduleVUEX3 = {
    export const state = { ... }
}

// Vuex 4.x Module
const moduleVUEX4 = {
    export const state = () => ({ ... })
}

单店:

// Vuex 3.x
import Vuex from 'vuex'

const store = new Vuex.Store({
  state: { ... }
})


// Vuex 4.x
import { createStore } from 'vuex'

const store = createStore({
  state() {
    return { ... }
  }
})

这个问题的解决方案是:

const vuexStore = createStore({
  state: return {
    posts: []
  }
})

【讨论】:

  • Vuex 4 state 可以是 either Object or Function。并且state 成为Object 而不是Function 并不是绝对必要的,并且它不会影响反应性(demo)。也就是说,如果您的应用使用模块的多个实例,则需要使用Function,以便每个实例都有自己的state
  • @tony19 感谢您指出 - 我的应用程序中确实有多个模块实例。
【解决方案2】:

我一般是这样用的

<script setup lang="ts">
import { computed, reactive,ComputedRef } from "vue";
import { useStore } from "vuex";
interface State {
  shadow: ComputedRef<boolean>
}
const store = useStore();

const state = reactive<State>({
  shadow: computed(() => store.state.shadow),
)}
</script>

当vuex中的状态发生变化时,页面会及时响应,希望对你有所帮助

【讨论】:

    【解决方案3】:

    您可以尝试删除 postsArray,我认为它与反应性有关。

    尝试将突变更改为

    addFirstPostsToVuex(state, docId) {
          state.posts.push(docId);
        }
    

    然后在你做的动作中

    for (const doc of firstPosts.docs) {
              commit("addFirstPostsToVuex",doc.id);
            }
    

    【讨论】:

      【解决方案4】:

      如果您使用 mapState 函数将 store 的状态映射到 Vue 组件的状态,则可以解决此问题。

      在上面的代码中,应该是这样的:

      import { mapState } from "vuex";
      import { defineComponent } from "vue";
      
      export default defineComponent({
           computed: {
              ...mapState(["posts"])
           }
      });
      

      v-for 现在应该可以正常工作了。

      参考:https://vuex.vuejs.org/guide/state.htmlhttps://scrimba.com/scrim/c8Pz7BSK?pl=pnyzgAP

      【讨论】:

      • 即使使用 mapState 也不起作用。
      猜你喜欢
      • 2022-01-25
      • 2018-06-13
      • 1970-01-01
      • 2021-07-11
      • 1970-01-01
      • 2022-01-25
      • 2021-02-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多