TS重写JS后,vue组件报错 [Vue warn]: Avoid mutating a prop directly......

一个vue组件原本功能逻辑正常,换成ts写法后就出了点问题,控制台报错如下(替换成ts写法后才有这报错):

image.png

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "info"

found in

---> <ArticleInfo> at src/components/article-info.vue

组件代码如下:

<template>
    <el-form label-width="48px">
        <el-form-item label="分类">
            <el-select class="article-info__catalog"
                       v-model="article.catalog"
                       filterable
                       :loading="isFetchingCatalog"
                       :no-data-text="emptyText"
                       @focus="fetchCatalogList()">
                <el-option v-for="catalog in catalogList"
                           :key="catalog.id"
                           :value="catalog.id"
                           :label="catalog.name">
                </el-option>
            </el-select>
        </el-form-item>
        <el-form-item label="作者">
            <el-input v-model="article.author"
                      :maxlength="30"
                      :show-word-limit="true">
            </el-input>
        </el-form-item>
        <el-form-item label="概览">
            <el-input v-model="article.desc"
                      type="textarea"
                      placeholder="100字内的简要介绍,选填"
                      :maxlength="100"
                      :rows="5"
                      resize="none"
                      :show-word-limit="true">
            </el-input>
        </el-form-item>
    </el-form>
</template>
import { Vue, Component, Prop, Watch } from 'vue-property-decorator';

@Component
export default class ArticleInfo extends Vue {
    @Prop()
    info: Object = {
        desc: '',
        catalog: '',
        author: ''
    };

    @Prop()
    catalogList: Array<Object> = [];

    @Prop()
    fetchCatalogListRequest: Function = ():Promise<string> => Promise.resolve('');

    isFetchingCatalog: boolean = false;
    emptyText: string = '';
    article: Object = {...this.info};

    @Watch('info')
    onInfoChanged (value: Object) {
        Object.assign(this.article, {...value});
    }

    getArticleInfo(): Object {
        return this.article;
    }

    async fetchCatalogList(): Promise<void> {
        this.isFetchingCatalog = true;
        this.emptyText = await this.fetchCatalogListRequest();
        this.isFetchingCatalog = false;
    }
};
export default {
    name: 'ArticleInfo',

    props: {
        info: {
            type: Object,
            default: () => {
                return {
                    desc: '',
                    catalog: '',
                    author: ''
                };
            }
        },

        catalogList: {
            type: Array,
            default: () => []
        },

        fetchCatalogListRequest: {
            type: Function,
            default: () => {}
        }
    },

    data () {
        return {
            article: {...this.info},
            isFetchingCatalog: false,
            emptyText: ''
        };
    },

    watch: {
        info (value) {
            this.$set(this, 'article', value);
        }
    },

    methods: {
        getArticleInfo () {
            return this.article;
        },

        async fetchCatalogList () {
            this.isFetchingCatalog = true;
            this.emptyText = await this.fetchCatalogListRequest();
            this.isFetchingCatalog = false;
        }
    }
};
阅读 4k
2 个回答

# 2个方法

第一个 :

// 父组件
<dialog-apply :visible.sync="dialogApplyVisible" />

// 子组件
<el-dialog
      :visible.sync="visible"
      title="申请"
      :before-close="onClose"
>

onClose() {
  this.$emit('update:visible', false)
}

第二个 :

// 父组件
<dialog-apply :visible.sync="dialogApplyVisible" @close='dialogApplyVisible = false' />

// 子组件
<el-dialog
      :visible.sync="visible"
      title="申请"
      :before-close="onClose"
>

onClose() {
  this.$emit('close')
}

这2个方法 , :before-close 是关键 ;

规避方式写法

import { Vue, Component, Prop, Watch } from 'vue-property-decorator';

@Component
export default class ArticleInfo extends Vue {
    @Prop({
        default: () => ({
            desc: '',
            catalog: '',
            author: ''
        })
    })
    info!: Object;

    @Prop({
        default: () => []
    })
    catalogList!: Array<Object>;

    @Prop({
        default: ():Promise<string> => Promise.resolve('')
    })
    fetchCatalogListRequest!: Function;

    isFetchingCatalog: boolean = false;
    emptyText: string = '';
    article: Object = {...this.info};

    @Watch('info')
    onInfoChanged (value: Object) {
        Object.assign(this.article, {...value});
    }

    getArticleInfo(): Object {
        return this.article;
    }

    async fetchCatalogList(): Promise<void> {
        this.isFetchingCatalog = true;
        this.emptyText = await this.fetchCatalogListRequest();
        this.isFetchingCatalog = false;
    }
};
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题