避免直接改变道具,因为该值将被覆盖
Posted
技术标签:
【中文标题】避免直接改变道具,因为该值将被覆盖【英文标题】:Avoid mutating a prop directly since the value will be overwritten 【发布时间】:2017-03-27 06:12:59 【问题描述】:我在升级到 Vue 2.0 时遇到非常常见的问题
我收到警告:
避免直接改变prop,因为值会被覆盖 每当父组件重新渲染时。相反,使用数据或 基于道具值的计算属性。道具被变异: “用户名”(在组件中找到)
我多次阅读文档,但我仍然无法理解如何修复它。
username
和 password
在主 Vue 应用程序中声明。
这是我的代码:
var GuestMenu = Vue.extend(
props : ['username', 'password'],
template: `
<div id="auth">
<form class="form-inline pull-right">
<div class="form-group">
<label class="sr-only" for="UserName">User name</label>
<input type="username" v-model="username" class="form-control" id="UserName" placeholder="username">
</div>
<div class="form-group">
<label class="sr-only" for="Password">Password</label>
<input type="password" v-model="password" class="form-control" id="Password" placeholder="Password">
</div>
</form>
</div>`,
);
App = new Vue (
el: '#app',
data:
topMenuView: "guestmenu",
contentView: "guestcontent",
username: "",
password: "",
)
我尝试了v-bind
,但它似乎不起作用,我不明白为什么。它应该将值绑定到父级(主 Vue 应用程序)
【问题讨论】:
请看这个问题***.com/questions/39868963/…,应该能帮到你 Vue 2 - Mutating props vue-warn的可能重复 【参考方案1】:从 Vue 2.3.0 开始,您可以使用 .sync
修饰符:
来自https://vuejs.org/v2/guide/components-custom-events.html#sync-Modifier的示例:
<text-document :title.sync="title"></text-document>
在你的控制器中...
this.$emit('update:title', newTitle)
【讨论】:
【参考方案2】:您应该使用 getter 和 setter 创建一个计算属性,然后使用$emit
更新该属性,例如:
var GuestMenu = Vue.extend(
props: ['username', 'password'],
template: `
<div id="auth">
<form class="form-inline pull-right">
<div class="form-group">
<label class="sr-only" for="UserName">User name</label>
<input type="username" v-model="usernameInput" class="form-control" id="UserName" placeholder="username">
</div>
<div class="form-group">
<label class="sr-only" for="Password">Password</label>
<input type="password" v-model="passwordInput" class="form-control" id="Password" placeholder="Password">
</div>
</form>
</div>`,
computed:
usernameInput:
get: function()
return this.username;
,
set: function(newValue)
this.$emit('update:username', newValue)
,
passwordInput:
get: function()
return this.password;
,
set: function(newValue)
this.$emit('update:password', newValue)
,
);
【讨论】:
这对我有用,但我必须从第一个答案中添加 .sync 位。【参考方案3】:Vue.js 认为这是反模式。例如,声明和设置一些 props,如
this.propsVal = 'new Props Value'
所以要解决这个问题,你必须从 Vue 实例的数据或计算属性的 props 中获取值。喜欢……
props: ['propsVal'],
data: function()
return
propVal: this.propsVal
;
,
methods:
...
你可以像往常一样使用你的 props 值。
【讨论】:
这不起作用 - 我在更改 this.propsVal 时仍然收到错误 @Gerfried 取决于变量的类型。如果你有一个对象/数组,它就不起作用,因为它只是一个新的引用。它仅适用于布尔值、字符串和数字等原语。如果你想让它工作,你必须克隆对象。例如。使用 lodash _.cloneDeep 或使用 JSON.parse(JSON.stringify(yourObjectProp))。【参考方案4】:我不确定您到底想达到什么目标,但我会从中选择两个选项。
第一个:一切都是为了摆脱这个警告。
data ()
return
childVal: this.parentVal
第二个:你想在父母和孩子之间进行交流。
如果我没记错的话,这是一个 <input>
在子组件中与其父组件通信的基本示例。
父 HTML:
<p> user </p>
<child-component v-model="user">
父 JS:
data ()
return
user: 'John'
子 HTML:
<input v-bind:value="value" @input="$emit('input', $event.target.value)">
儿童 JS:
props: ['value']
工作示例:http://jsfiddle.net/kf3aLr1u/
您还可以在文档https://vuejs.org/v2/guide/components.html 中阅读更多相关信息。
【讨论】:
【参考方案5】:如果你想改变道具 - 使用对象。
<component :user="global.user"></component>
组件:
props: ['user'],
methods:
setUser: function()
this.user.username= "User";
this.user.password= "myPass123";
【讨论】:
你不应该使用对象来“绕过”这个警告。相反,您根本不应该修改道具,而是将它们分配给本地可变的“数据”属性。如果你需要修改全局数据,你应该考虑Vuex,但无论你如何处理全局,你都不应该编辑props。 我正在使用道具将组件中的状态别名为小组件。我想改变这个组件中的道具。在纯函数方面:我有很多纯函数可以操作单个不纯函数。我讨厌函数式编程中的这些 vue 雏形。 React + MobX 没有这种垃圾。 @DaveGoodchild 您在重申 vue.js 文档/团队中的“派对路线”时 100% 正确,例如访问 [本指南] (vuejs.org/v2/guide/comparison.html) 并搜索“意见”,您会看到他们将 vue 作为“无意见”的框架/库出售。然后在整个社区/文档中,我看到极端的“意见”表现为硬的“事实”。我希望我的组件改变道具。我不希望发出数百个事件的 Vuex/样板代码的复杂性。但这不是vue团队的“意见”。至少他们已经从主页上删除了“无主见”。 给猫剥皮的方法有很多,但在 vue 世界中只有一种! 例如看过vue的原作者说html表单中从来没有隐藏字段的用例!!!!!!我不敢苟同。【参考方案6】:具有适当 get
和 set
的 computed
属性为我工作:
computed:
dialogDataProp:
get: function()
return this.dialog;
,
set: function()
上面用于切换对话框的代码。
【讨论】:
你能提供完整的父子道具事件吗?这是一个子计算属性吗?你如何设置你的父母? 所以,它是<v-dialog v-model="dialogDataProp">
,我按照Vuetify 使用它 - 并且有get
和set
来控制切换。
对不起,这里还有props: dialog: type: Boolean, default: false
,'parent' 正在为prop :dialog
传递值。但是,我们不会改变 prop
- 我们使用 computed
,如图所示。
我也使用 vuetify 的 v-dialog,但是当对话框单击外部并关闭对话框时,对话框的状态不会变为 false。
感谢您的回复,现在我终于可以使用 set() 在父级中传递 false 值并将对话框值更改为父级,以便我现在可以使用道具切换 v-dialog
【参考方案7】:
如果你的道具是一个物体,快速解决方案。
您可以避免使用$emit
或在javascript 中使用Object.assign()
来避免出现该错误。
这与v-model
属性的作用相同。
示例:
// Update the user
Object.assign(this.userProp, user);
【讨论】:
【参考方案8】:你可以使用emit,那么:
<text-document :title.sync="title"></text-document>
改变值是:
this.$emit('update:title', newTitle)
或其他方式:
this.$emit('update')
你可以上模板:
<text-document :update="oneFunctionInMethods()"></text-document>
【讨论】:
【参考方案9】:当您使用 v-bind
时,该属性使用两个方向绑定,这就是您收到警告的原因。
如果需要从父级Vue组件传递初始用户名,可以使用v-bind
和另一个数据属性如_username
,并在组件创建时将初始值从属性复制到内部数据:
props : ['username', 'password'],
data ()
return
_username: this.username,
_password: this.password
编辑:您还可以使用 $watch 在属性更改时更新 _username / _password 组件数据。
【讨论】:
我是否正确理解this.username
中的 this
指向父级?
this
指向属性用户名和密码(当前组件),虽然我不明白unexpeced token :
错误
TiagoLr,“来自父级Vue组件”不是来自父级,而是来自父级。用户指定后,应将其发送给父级。
啊,那我很糟糕,要从孩子与父母交流,您应该使用事件:vuejs.org/v2/guide/…。您也可以使用this.$parent
,尽管这不是推荐的模式。
其实要拥有一个更灵活的应用你需要使用vuex和store patterngithub.com/vuejs/vuex【参考方案10】:
var GuestMenu = Vue.extend(
props :
uNpW:type:Object
template: `
<div id="auth">
<form class="form-inline pull-right">
<div class="form-group">
<label class="sr-only" for="UserName">User name</label>
<input type="username" v-model="uNpW.username" class="form-control" id="UserName" placeholder="username">
</div>
<div class="form-group">
<label class="sr-only" for="Password">Password</label>
<input type="password" v-model="uNpW.password" class="form-control" id="Password" placeholder="Password">
</div>
</form>
</div>`,
);
App = new Vue (
el: '#app',
data:
topMenuView: "guestmenu",
contentView: "guestcontent",
unAndPw:username: "",password: ""
)
in main html
<guest-menu :uNpW=unAndPw> </guest-menu>
你不需要发射或任何其他东西
【讨论】:
【参考方案11】:按照这个非常简单的说明进行操作:
//Parent Component
<InsertForm :formSchema="formSchema" v-on:getFormSchema="setFormSchema"></InsertForm>
<script>
import InsertForm from "./insertForm.vue"; //select file
export default
components: InsertForm ,
data: () => (
formSchema:
id:'',
webUrl:''
,
),
methods:
setFormSchema(data)
this.formSchema = data.formSchema;
</script>
// From Child Component. That means from insertForm.vue file
<script>
export default
props: ["formSchema"],
data: () => (
),
//Where you need
this.$emit("getFormSchema", 'formSchema':"id":1,"webUrl":"bdprescription.com");
</script>
【讨论】:
以上是关于避免直接改变道具,因为该值将被覆盖的主要内容,如果未能解决你的问题,请参考以下文章