哪种方法将元素添加到 Vuex 状态属性的数组属性是正确的?

Posted

技术标签:

【中文标题】哪种方法将元素添加到 Vuex 状态属性的数组属性是正确的?【英文标题】:Which method of adding an element to the array property of a Vuex state property correct? 【发布时间】:2022-01-14 16:30:48 【问题描述】:

所以我有一个动作,它向为特定艺术品创建评论的端点发出 POST 请求。在渲染艺术品及其 cmets 的组件上,我在 onMounted() 钩子中调度一个操作,该操作对具有该 id 的艺术品发出 GET 请求,然后将其存储在 Vuex 中。

一旦创建评论的 POST 请求通过,我就可以访问商店中的艺术品属性,并将响应推送到 cmets 属性,该属性是一个 cmets 数组。我不知道这是否是正确的方法,因为据我所知,任何状态更改都应该通过突变来完成,所以直接访问状态并将数组元素推入它似乎不正确?

这是我创建评论并将响应推送到所选艺术品的 cmets 属性的操作:

    async createComment(commit, state, payload)
        try 
            let response = await axios.post("/createComment", payload)
            console.log(response)
            state.image.comments.push(response.data.comment)
         catch (error) 
            console.log(error)
        
    ,

我猜另一种方法是从状态中复制艺术品,在副本的 cmets 属性中推送新评论,然后提交新对象?

【问题讨论】:

【参考方案1】:

您可以创建突变:

const mutations = 
  addComment(state, comment) 
    state.image =  
      ...state.image,
      comments: [ ...state.image.comments, comment]
    
  ,
,

然后从你的行动中提交:

async createComment(commit, state, payload)
    try 
        let response = await axios.post("/createComment", payload)
        console.log(response)
        commit('addComment', response.data.comment);
     catch (error) 
        console.log(error)
    
,

【讨论】:

但是我没有状态属性 cmets。 cmets 数组是图像状态属性的一个属性【参考方案2】:

从状态中获取一个对象并改变它的属性违反“一个真实来源”的原则对于所有的变化,这是为什么您首先要使用商店。 您必须将状态中的对象替换为自身的修改版本。在您的情况下,突变可能如下所示:

this.$store.commit('ADD_COMMENT', comment);
// in store:
mutations: 
  ADD_COMMENT(state, comment) 
    state.image =  
      ...state.image,
      comments: [ ...(state.image.comments || []), comment]
    
  

这也可以通过push-ing 将注释添加到现有的comments 数组中来实现。但是你还是要换state.image

// ❌ WRONG, you're not replacing the image:
state.image.comments.push(coment);

// ✅ CORRECT, you're replacing the image:
const clone =  ...state.image ;
clone.comments.push(comment);
state.image = clone;

// that's why most prefer the spread syntax, 
// to assign in one line, without using a const: 
// state.image =  ...state.image, [yourKey]: yourNewValue ;

重要:变异状态应该只发生在变异函数内部。如果它发生在外面,Vue 会警告你。有时它可能会起作用(例如,您实际上可能会看到组件中的变化并且它可能会正确呈现),但不能保证它会起作用。


更新状态数组中的对象的示例:

如果图像是存储在状态中的数组的一部分(比如images),并且考虑到每个图像都有一个唯一标识符id,那么您可以这样做:

this.$store.commit('ADD_IMAGE_COMMENT',  id: image.id, comment );

// the mutation:
mutations: 
  ADD_IMAGE_COMMENT(state,  id, comment ) 
    const index = state.images.findIndex(image => image.id === id);
    if (index > -1) 
      state.images.splice(index, 1,  
        ...state.images[index],
        comments: [...(state.images[index].comments || []), comment]
      );
    
  

上述突变改变了images 数组,有效地将其替换为自身的新副本,其中包含所有其他未修改的图像以及与旧图像相同索引处的修改后图像的新版本。修改后的图像包含旧图像包含的所有内容,除了 cmets 数组,替换为一个新数组,包含旧数组的所有内容以及新注释。

【讨论】:

以上是关于哪种方法将元素添加到 Vuex 状态属性的数组属性是正确的?的主要内容,如果未能解决你的问题,请参考以下文章

Vuex 状态数组对象的计算属性

javascript数组属性及方法

Vuex 状态更改不会刷新 Vue on Web

在 Vuex 中基于状态属性进行计算的正确方法是啥?

使用 Vue + Vuex 在渲染之前无法获取对象的状态属性

vuex使用方法