错误:vuex不会随着上传图片而在突变处理程序之外对vuex存储状态进行突变

时间:2020-07-19 13:38:47

标签: vue.js vuejs2 vuex nuxt.js

我有点卡住了。每当我尝试更新商店时,都会收到此错误。我正在做的是,我获取我的产品并将其存储。在此创建的上载图像部分(组件)中,将图像填充有状态以显示已上载的图像,然后在每次上载时通过调度和更改来更改我的状态。我知道当我用状态填充数据时,它与created()有关,但不知道如何解决。

这是我的模板:

<v-card flat class="pb-4" max-width="450px">
  <v-img class="rounded-lg theme__main__color" :src="url"></v-img>
  <v-list container inline class="transparent text-center pa-0">
    <v-list-item class="px-0">
      <v-list-item class="px-1">
        <v-btn
        width="100%"
        class="theme__btn__w text_main_color"
        :loading="isSelecting"
        @click="onChooseClick"
        >{{lang.chooseimage}}</v-btn>
      </v-list-item>
      <v-list-item class="px-1">
        <v-btn
        width="100%"
        class="theme__btn__s text_main_color"
        @click.prevent="uploadImage"
        >{{lang.upload}}</v-btn>
        <input
        ref="uploader"
        class="d-none"
        type="file"
        accept="image/*"
        @change="onFileChanged"
        >
      </v-list-item>
    </v-list-item>
  </v-list>
</v-card>

这是我的脚本:

export default {
    data(){
        return{
            isSelecting: false,
            selectedFile: null,
            url: null,
            placeholder: '/images/placeholder/place-800.png',
            section: 'img',
            pimages: [],
            pId: null
        }
    },
    methods:{
        onChooseClick(){
            this.isSelecting = true
            window.addEventListener('focus', () => {
                this.isSelecting = false
            }, { once: true })

            this.$refs.uploader.click()
        },
        onFileChanged(e) {
            this.selectedFile = e.target.files[0]
            this.url = URL.createObjectURL(this.selectedFile)
            // do something
        },
        async uploadImage(){
            if(this.notEmpty(this.selectedFile) && this.notEmpty(this.pId)){
                const data = new FormData()
                data.append('image', this.selectedFile)
                data.append('pId', this.pId)
                // let response = await this.axiosPost('product/createproimg', data)
                this.pimages.push({"url": this.url})
                this.url = this.placeholder
                this.setEditProductImg(this.pimages)
            }
        }
    },
    created(){
        this.url = this.placeholder
        this.pId = this.editProduct.pId
        this.pimages = this.editProduct.images
        this.$nuxt.$on('insert',(section)=>{
            if(section === 'desc' && !this.pId){
                this.pId = this.editProduct.pId
            }
        })
    }
}

当然还有我的商店

state:
editProduct: {
    pId: null,
    images: []
  }

getter:
editProduct(state){
    return state.editProduct
  }

mutation:
SET_EDITPRODUCT_IMG(state, img){
    state.editProduct.images = img
  },

action:
setEditProductImg({commit}, img){
    commit('SET_EDITPRODUCT_IMG', img)
  },

更新 感谢@skirtle,以上问题已解决!但在其他方面却出现了新的相同错误。正如@skirtle的建议,使用const来改变我的状态,但会出错。更清楚地说,我的状态是一个空数组,它将在第一次填充,但是如果我什至尝试更改我的选择,我就会收到错误!!!更alone论发送另一个突变!这是代码:

<template>
<div class="pt-6">
    <v-row class="ma-0">
    <v-col cols="12" md="12" class="pa-0">
        <v-row class="ma-0">
        <!-- form 1 -->
            <template v-for="(select, index) in selects">
                <component
                :is="select"
                :key="select.name"
                v-model="catId"
                @changed="addComponent(index)"
                :catid="catId"
                :selectindex="index"
                :pcat="productCat[index]"
                :subcat="subCat"
                ></component>
            </template>
        <!-- btn -->
        <v-col cols="12" sm="6" md="3" class="px-1">
            <v-btn width="100%" class="theme__little__color2 text_main_color px-2" @click.prevent="addCatBtn()">{{lang.addcat}}</v-btn>
        </v-col>
        {{selectedCatArr}}
        <!-- btn -->
        <addproductbtn :section="section" />
        </v-row>
    </v-col>
    </v-row>
</div>
</template>

<script>
import addproductbtn from '~/components/global/cms/addproductbtn'
import selectcategory from '~/components/global/cms/selectcategory'

export default {
    components:{
        'addproductbtn': addproductbtn
    },
    data(){
        return{
            section: 'cat',
            selects: [selectcategory],
            catId: 0,
            subCat: true,
            selectedCatArr: []
        }
    },
    methods:{
        addComponent(index){
            
                this.selects.length = index + 1
                setTimeout(() => {
                    this.selects.push(selectcategory)
                }, 1);
            
        },
        addCatBtn(){
            this.goToRedirect('/cms/category/insert', this.$route.path, this.ProductId)
        },
        async insertCategory(){
            const data = {
                pId: this.editProduct.pId,
                catId: this.catId
            }
            // let response = await this.axiosPost('product/catupdate', data)
            const productCategory = this.selectedCatArr
            this.setEditProductCat(productCategory)
        }
    },
    computed:{
        productCat(){
            return this.editProduct.categories
        },
        ProductId(){
            return this.editProduct.pId
        }
    },
    created(){
        this.$nuxt.$on('insert', ()=>{
            this.insertCategory()
        })
        this.$nuxt.$on('nextcat', (subCat)=>{
            this.subCat = subCat
        })
        this.$nuxt.$on('nextpanel', ()=>{
            this.insertCategory()
        })
        this.$nuxt.$on('selectedcat', (selected, index)=>{
            delete selected.subCategory
            this.selectedCatArr.length = index
            this.selectedCatArr.push(selected)
        })
    }
}
</script>

和我的选择组件:

<template>
    <v-col cols="12" sm="6" md="3" class="px-1 text_details_color3" v-if="showCat">
        <v-select
        return-object
        :items="items"
        :label="lang.category"
        v-model="selected"
        @change="emitEvent"
        item-text="title"
        item-value="id"
        outlined></v-select>
        {{selected}}
    </v-col>
</template>

<script>
export default {
    props:['selectindex','catid','pcat','subcat'],
    data(){
        return{
            selected:{},
            items:[],
            showCat: true
        }
    },
    async fetch(){
        // this.items = await this.axiosGet(`categories/${this.catid}/1`)
        this.items = [
            {id: this.catid + 1, title: this.catid+'title1', subCategory: true},
            {id: this.catid + 2, title: this.catid+'title2', subCategory: true},
            {id: this.catid + 3, title: this.catid+'title3', subCategory: false},
            {id: this.catid + 4, title: this.catid+'title4', subCategory: true}
        ]
    },
    methods:{
        emitEvent(){
            this.$emit('input', this.selected.id)
            this.$emit('changed')
            $nuxt.$emit('nextcat', this.selected.subCategory)
            $nuxt.$emit('selectedcat', this.selected, this.selectindex)
        }
    },
    computed:{
        //
    },
    created(){
        
    },
    mounted(){
        this.selected = this.pcat
        this.showCat = this.subcat
    }
}
</script>

1 个答案:

答案 0 :(得分:1)

我相信问题是这行:

this.pimages.push({"url": this.url})

数组this.pimages与商店状态内的数组相同,通过调用push可以在商店外部进行修改。

有两种方法可以解决此问题。

一种方法是在突变内执行push,例如通过进行ADD_EDITPRODUCT_IMG突变:

mutation:
  ADD_EDITPRODUCT_IMG(state, img){
    state.editProduct.push(img)
  },

然后,您将使用与当前突变几乎相同的方式来调用它,只是将新图像传递给它以添加而不是传递整个数组。

一种与您当前所拥有的方法更接近的替代方法是复制数组而不是修改原始数组:

const newImages = [...this.pimages, {"url": this.url}]

this.setEditProductImg(newImages)

使用这种方法,您不需要对现有商店进行任何更改。

更新

我还建议将pimages设为计算属性。似乎没有充分的理由通过created挂钩将数据“复制”到存储状态之外。