子组件不能直接改变父组件传递的“道具”值

        引言:

        不少人在刚开始使用vue时都会遇到一个报错——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.避免直接改变道具,因为当父组件重新渲染时,该值将被覆盖。相反,使用基于道具值的data或computed属性。)

        这个问题是因为在 Vue.js 中,数据流是单向的,父组件通过 props 将数据传递给子组件,子组件中不能直接修改父组件传递进来的值。那么我们该如何去解决呢?

一、场景举例

        大家在开发中会经常对Dialog弹窗进行二次封装,从而便于我们在多个页面使用,这个时候我们就需要在父组件中控制Dialog弹窗的展示,同时还需要在子组件Dialog中将自己关闭。这种情况下就可能会出现上面的报错。

例:

        在父组件中引入一个封装过的Dialog弹窗组件,并向子组件传递所需参数,此时我们默认showDialog为true。

<template>
	<div>
		<satisfactionDialog
			:showDialog="showDialog"
			@cancel="showDialog = false"
			@affirm="showDialog = false"
			@close="showDialog = false"
            affirm-text="确认"
			cancel-text="取消"
			title="子组件标题"
		>
			<!--			<div style="height: 200px"></div>-->
		</satisfactionDialog>
	</div>
</template>

<script>
import satisfactionDialog from "XXXXXXX";

export default {
	data() {
		return {
			showDialog: true,
		};
	},
	methods: {
	},
	components: { satisfactionDialog },
};
</script>

         子组件中接受父组件传递的参数,此时子组件为展示状态。

<template>
	<div>
		<van-dialog v-model="showDialog" width="82%" :show-confirm-button="false" :overlay="overlay" title>
			<div class="content">
				<img src="@/views/assets/close_icon.png" @click="close" alt="" />
				<header>
					{{ title }}
				</header>
				<slot></slot>
				<footer>
					<div class="cancel">
						<van-button type="info" @click="cancel">{{ cancelText }}</van-button>
					</div>
					<span></span>
					<div>
						<van-button type="info" @click="affirm">{{ affirmText }}</van-button>
					</div>
				</footer>
			</div>
		</van-dialog>
	</div>
</template>
<script>
export default {
	name: "satisfactionDialog",
	props: {
		showDialog: Boolean,
		cancelText: String, //取消按钮文案
		affirmText: String, //确认按钮文案
		title: String, //标题文案
		overlay: {
			//是否显示遮罩层
			type: Boolean,
			default: true,
		},
	},
};
</script>

        我们要在子组件中关闭Dialog弹窗,此时方法应该怎样写? 

        可能有同学会写:

methods: {
		// 取消事件
		cancel() {
			this.showDialog = false;
		},
		//确认事件
		affirm() {
			this.showDialog = false;
		},
		close() {
			this.showDialog = false;
		},
	},

        去年刚入职的我也是这样写的。。。此时我们就会发现控制台报错了,报错的原因正是: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.避免直接改变道具,因为当父组件重新渲染时,该值将被覆盖。相反,使用基于道具值的data或computed属性。)

二、解决方法

 那么我们应该怎样去写呢?这里给大家几种方法:

       1、通过this.$emit去调用父组件的自定义方法,这样便可以控制数据流向永远都是通过父组件改变值来改变子组件的显示。
methods: {
		// 取消事件
		cancel() {
			this.$emit("cancel");
		},
		//确认事件
		affirm() {
			this.$emit("affirm");
		},
		close() {
			this.$emit("close");
		},
	},
        2、使用自定义v-model一劳永逸,就不需要再关注父子传参了。

        在父组件中使用v-model="showDialog"代替:showDialog="showDialog",注意子组件中的写法:

        首先需要设置model属性:

model: {   //在这里设置model绑定的值的对应关系
		prop: "showDialog",
		event: "change",  //定义触发的方法
	},

        props中需要正常接收 :

props: {
		showDialog: Boolean,  //注意这里需要正常接收父组件传递的值
	},

        通过调用定义好的event方法来改变值:

methods: {
		// 取消事件
		cancel() {
			this.$emit("change", false);
		},
		//确认事件
		affirm() {
			this.$emit("change", false);
		},
		close() {
			this.$emit("change", false);
		},
	},

关于自定义v-model大家也可以参考我的另一篇文章中的讲解自定义子组件的v-model

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端小菜凯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值