【问题标题】:Vuex & VueJS (Do not mutate vuex store state outside mutation handlers)Vuex 和 VueJS(不要在突变处理程序之外改变 vuex 存储状态)
【发布时间】:2016-11-16 19:58:10
【问题描述】:

我正在尝试创建一个 listenAuth 函数来监视 firebase 中的“onAuthStateChanged”以通知 vuex 商店 当用户登录或退出时。据我所知,我只是在使用突变处理程序修改 state.authData,除非我遗漏了什么?

我收到错误消息:

[vuex] Do not mutate vuex store state outside mutation handlers.

这是我的 App.vue javascript(来自我的组件)

<script>
// import Navigation from './components/Navigation'
import * as actions from './vuex/actions'
import store from './vuex/store'
import firebase from 'firebase/app'

export default {
  store,
  ready: function () {
    this.listenAuth()
  },
  vuex: {
    actions,
    getters: {
      authData: state => state.authData,
      user: state => state.user
    }
  },
  components: {
    // Navigation
  },
  watch: {
    authData (val) {
      if (!val) {
        this.redirectLogin
        this.$route.router.go('/login')
      }
    }
  },
  methods: {
    listenAuth: function () {
      firebase.auth().onAuthStateChanged((authData) => {
        this.changeAuth(authData)
      })
    }
  }
}
</script>

这是我的操作(changeAuth)函数

export const changeAuth = ({ dispatch, state }, authData) => {
  dispatch(types.AUTH_CHANGED, authData)
}

这是我的商店(重要的部分)

const mutations = {
  AUTH_CHANGED (state, authData) {
    state.authData = authData
  }
}

const state = {
  authData: {}
}

【问题讨论】:

  • 你可能想升级到 Vuex 2.0

标签: javascript firebase vue.js firebase-authentication vuex


【解决方案1】:

我也遇到过这个问题。我的商店:

  state: {
    items: []
  },
  mutations: {
    SetItems (state, payload) {
      // Warning
      state.items = payload.items
    }
  },
  actions: {
    FetchItems ({commit, state}, payload) {
      api.getItemsData(payload.sheetID)
        .then(items => commit('SetItems', {items}))
    }
  }

state.items = payload.items 替换为:

state.items = payload.items.slice()

原因是数组作为引用存储在 Javascript 中,payload.items 很可能在 Vuex 之外被更改。所以我们应该 只需使用 payload.items 的新副本即可。

对于状态对象,使用:

state.someObj = Object.assign({}, payload.someObj)

并且不要使用JSON.parse(JSON.stringify(someObj)),因为它要慢得多。

【讨论】:

    【解决方案2】:

    在解决了同样的问题后,我发现只有当我们尝试将 auth/user 数据存储在 Vuex 状态时才会发生错误。

    改变...

    const mutations = {
      AUTH_CHANGED (state, authData) {
        state.authData = authData
      }
    }
    

    ...到...

    const mutations = {
      AUTH_CHANGED (state, authData) {
        state.authData = JSON.parse(JSON.stringify(authData))
      }
    }
    

    会解决你的问题。

    【讨论】:

    • 请改用state.authData = Object.assign({}, authData)。看看我下面的答案。
    • 由于某种原因 Object.assign({}, authData) 不起作用,但 JSON.parse(JSON.stringify(authData)) 起作用。
    • Object.assign 有时不起作用的原因是因为它不执行深层复制,如文档 "For deep cloning, we need to use other alternatives because Object.assign() copies property values. If the source value is a reference to an object, it only copies that reference value." 中所述。对于深度克隆,JSON.parse(JSON.stringify(obj)) 更好,即使它肯定会更慢
    • 赞成建议的替代方案,也适用于我的身份验证
    • 我想问为什么这个解决方案有效,因为没有解释。
    【解决方案3】:

    我也有这个问题,我用lodash克隆数据

    state.someStatehere = $lodash.cloneDeep(data)
    

    【讨论】:

      【解决方案4】:

      所以从许多答案中我们可以就原因达成一致:存储在状态中的对象被持有对它的引用的东西默默地修改。许多人建议制作对象的副本。

      另一种选择是在修改对象时清空状态。当由于某种原因您无法复制对象时,此方法有效。 例如:

      bla({ state } {}) {
        mutatingMethod(state.xxx);
      },
      

      如果您知道mutatingMethod 正在修改 xxx,那么您可以这样做:

      bla({ state } {}) {
        let xxx = state.xxx
        commit("SET_XXX", null)
        mutatingMethod(xxx);
        commit("SET_XXX", xxx)
      },
      

      【讨论】:

        【解决方案5】:

        对于同样为此苦苦挣扎的任何人,这是解决它的另一种方法(实际上对我有用):

        auth()
          .onAuthStateChanged((user) => {
            if (user) {
              commit(MUTATION_TYPES.SET_USER, { ...user.toJSON() });
            }
          })
        

        【讨论】:

          猜你喜欢
          • 2019-09-24
          • 2018-02-13
          • 2022-01-09
          • 1970-01-01
          • 2020-03-30
          • 2023-03-09
          • 1970-01-01
          • 1970-01-01
          • 2019-11-30
          相关资源
          最近更新 更多