【问题标题】:Vuejs2 axios mutation: update an objectVuejs2 axios 突变:更新一个对象
【发布时间】:2021-04-20 00:53:43
【问题描述】:

我有以下 user.js 文件“有效”但需要改进:

import * as mutationTypes from "../mutation-types";
import user from "./user_data";

export const state = user;

export const getters = {
  user: (state) => state
};

export const mutations = {
  [mutationTypes.SET_USER]: (state, payload) => {
    state.username = payload.username;
    state.avatar=payload.avatar;
    state.locale=payload.locale;
    state.currency=payload.currency;
    state.userid=payload.userid;
  }
};

export const actions = {
  setUser: ({ commit }, payload) => {
    commit(mutationTypes.SET_USER, payload);
  }
};

通过 axios 我收到了这个代表完整用户的有效负载,因此是状态:

payload:{
    userid: "EA7FD2025132E3254A11FE70E9746A52",
    username: "boss",
    level:  6,
    active: true,
    company:'mySite ltd',
    landingpage:'dashboard',
    locale:'es',
    currency:'eur',
    subscriptionlevel:'',
    subscriptionexpiry:'',
    credits:0,
    name: "John Doe",
    email: "john.doe@mysite.com",
    avatar: "/static/avatar/john.jpg",
    job: "mySite - FOUNDER & CEO",
  }

如何在不更新单个子参数的情况下完全更新状态 即是这样的:

export const mutations = {
  [mutationTypes.SET_USER]: (state, payload) => {
    state = payload;
  }
};

我试过了

state = Object.assign({}, payload)

但它不起作用:-(

这里是 vuex 状态:

【问题讨论】:

    标签: vuejs2


    【解决方案1】:

    Vuex 中的状态和相关功能(mutations、getter 等)被设想为包含多条信息、多个切片,您可以使用它们来管理应用程序状态。

    一次改变整个状态是一个不寻常的用例:如果可能的话,我会回答自己。

    由于@Dan 在他/她的回答中解释的原因,当您在 mutation 方法中将 Javascript 对象指向新对象时,原始对象不会更改,而是传递给该方法的引用指向payload 在您的示例中。结果,原始对象没有改变。 Dan Abramov 在他的 Just Javascript 博客文章中写了一篇关于突变的精彩文章:请,如果你有时间,我建议你查看它们。

    因此,与其尝试改变整个state,不如只改变一个片段,比如state.user

    为了让它正常工作,你需要初始化Vuex state如下(假设user是从外部文件导入的):

    export const state = {
      user: user
    }
    

    或者更简洁,使用ES6 object property values shorthand syntax

    export const state = {
      user
    }
    

    您可以根据需要在此处定义任意数量的属性,以反映您的实际应用程序状态并用初始值填充它们。

    然后,您可以安全地在相应的mutation 上对这个切片进行变异:

    export const mutations = {
      [mutationTypes.SET_USER]: (state, payload) => {
        state.user = payload;
      }
    };
    

    你还需要修改相关的getters

    export const getters = {
      user: (state) => state.user
    };
    

    【讨论】:

    • 对不起@Joe。问题可能与 Vue 维护状态的方式有关,Dan 在他/她的回答中也解释了上下文。请问,您可以尝试建议的新方法吗?
    • 嗨!该解决方案似乎有效。实际上user 是一个“子”状态,因为它位于单独的.js 文件中,我想至少了解它是如何工作的,将其更改为state.user,但到目前为止我所有的尝试都失败了:-(
    • 刚刚添加了vuex状态截图
    • 还有@Joe,你试试state.user = payload还是不行?
    • 不,state.user = payload 是我的第一次尝试,但它很好地将对象user 添加到状态中,实际上这是@Dan 建议我做的......但我不知道如何在开头创建state.user :-(
    【解决方案2】:

    为什么不起作用

    当你重新分配一个已经包含一个对象的变量时,它不会改变现有的对象,只会将变量指向一个新的对象。旧的参考连接丢失。因此,在突变中重新分配 state 对实际的底层 state 对象没有任何作用。使用 =Object.assign... 扩展运算符没有区别。

    最好将用户对象置于state.user这样的状态:

    state = payload  // ❌ Only reassigns the variable reference, no changes to original
    
    state.user = payload  // ✅ Changing a reference property via the parent reference
    

    另一种看待它的方式是记住函数中的state不一定总是与模块中的state相同,实际上它是shadows

    不直接使用state对象的一些原因:

    1. 在突变中更难改变它。
    2. 更难与mapState helper 一起使用
    3. 代码可读性/可测试性

    store.replaceState

    如果您仍想以这种方式使用 state,并且您没有使用 Vuex 模块,有时可以使用 store.replaceState 轻松完成。也可以用模块来完成,但有点棘手:

    export const mutations = {
      [mutationTypes.SET_USER]: (state, payload) => {
        this.replaceState(payload);
      }
    };
    

    【讨论】:

    • hmm.. 这是因为对象不是原始数据类型,所以它只被引用?好吧,它不起作用,但会根据您的建议尝试修改结构谢谢
    • 仍然无法正常工作:返回 Uncaught (in promise) TypeError: Cannot read property 'replaceState' of undefined 谢谢
    • 我不知道你是如何设置你的商店的 this 是未定义的,但这没关系,因为 replaceState 在使用 Vuex 模块时有点棘手。但正如我所说,我建议不要像那样直接使用state。回答你的第一个问题:对于原语来说也是一样的。任何变量的重新赋值对使用指向的任何变量都没有任何作用。
    猜你喜欢
    • 1970-01-01
    • 2020-06-01
    • 2023-03-12
    • 1970-01-01
    • 2019-08-25
    • 2021-10-12
    • 2022-10-31
    • 2017-07-28
    • 2020-08-13
    相关资源
    最近更新 更多