Javascript Vue 2 - 改变道具 vue-warn
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/39868963/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Vue 2 - Mutating props vue-warn
提问by Dariusz Chowański
I started https://laracasts.com/series/learning-vue-step-by-stepseries. I stopped on the lesson Vue, Laravel, and AJAXwith this error:
我开始了https://laracasts.com/series/learning-vue-step-by-step系列。我在学习Vue、Laravel 和 AJAX时遇到了这个错误:
vue.js:2574 [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: "list" (found in component )
vue.js:2574 [Vue 警告]:避免直接改变 prop,因为每当父组件重新渲染时,该值将被覆盖。相反,根据道具的值使用数据或计算属性。正在变异的道具:“列表”(在组件中找到)
I have this code in main.js
我在main.js 中有这段代码
Vue.component('task', {
template: '#task-template',
props: ['list'],
created() {
this.list = JSON.parse(this.list);
}
});
new Vue({
el: '.container'
})
I know that the problem is in created()when I overwrite the list prop, but I am a newbie in Vue, so I totally don't know how to fix it. Anyone have an idea how (and please explain why) to fix it?
我知道当我覆盖列表道具时问题出在created() 中,但我是 Vue 的新手,所以我完全不知道如何解决它。任何人都知道如何(并请解释原因)修复它?
回答by ira
This has to do with the fact that mutating a prop locally is considered an anti-pattern in Vue 2
这与在 Vue 2 中本地改变 prop 被认为是反模式的事实有关
What you should do now, in case you want to mutate a prop locally, is to declare a field in your data
that uses the props
value as its initial value and then mutate the copy:
你现在应该做的是,如果你想在本地改变一个 prop,是在你的一个字段中声明一个data
使用该props
值作为其初始值的字段,然后改变副本:
Vue.component('task', {
template: '#task-template',
props: ['list'],
data: function () {
return {
mutableList: JSON.parse(this.list);
}
}
});
You can read more about this on Vue.js official guide
您可以在Vue.js 官方指南中阅读更多相关信息
Note 1:Please note that you should notuse the same name for your prop
and data
, i.e.:
注1:请注意,您应该不为你使用相同的名称prop
和data
,即:
data: function () { return { list: JSON.parse(this.list) } // WRONG!!
Note 2:Since I feel there is some confusionregarding props
and reactivity, I suggest you to have a look on thisthread
回答by chris
The Vue pattern is props
down and events
up. It sounds simple, but is easy to forget when writing a custom component.
Vue公司的模式是props
下来events
了。这听起来很简单,但在编写自定义组件时很容易忘记。
As of Vue 2.2.0 you can use v-model(with computed properties). I have found this combination creates a simple, clean, and consistent interface between components:
从 Vue 2.2.0 开始,您可以使用v-model(带有计算属性)。我发现这种组合在组件之间创建了一个简单、干净且一致的接口:
- Any
props
passed to your component remains reactive (i.e., it's not cloned nor does it require awatch
function to update a local copy when changes are detected). - Changes are automatically emitted to the parent.
- Can be used with multiple levels of components.
props
传递给您的组件的任何内容都保持反应性(即,它不会被克隆,也不需要watch
在检测到更改时更新本地副本的函数)。- 更改会自动发送到父级。
- 可以与多个级别的组件一起使用。
A computed property permits the setter and getter to be separately defined. This allows the Task
component to be rewritten as follows:
计算属性允许分别定义 setter 和 getter。这允许Task
组件重写如下:
Vue.component('Task', {
template: '#task-template',
props: ['list'],
model: {
prop: 'list',
event: 'listchange'
},
computed: {
listLocal: {
get: function() {
return this.list
},
set: function(value) {
this.$emit('listchange', value)
}
}
}
})
The modelproperty defines which prop
is associated with v-model
, and which event will be emitted on changes. You can then call this component from the parent as follows:
的模型,其属性定义prop
相关联v-model
,并且该事件将在改变发射。然后,您可以从父级调用此组件,如下所示:
<Task v-model="parentList"></Task>
The listLocal
computed property provides a simple getter and setter interface within the component (think of it like being a private variable). Within #task-template
you can render listLocal
and it will remain reactive (i.e., if parentList
changes it will update the Task
component). You can also mutate listLocal
by calling the setter (e.g., this.listLocal = newList
) and it will emit the change to the parent.
所述listLocal
计算出的属性在组件内提供了一个简单的getter和setter接口(认为它像被一个私有变量)。在#task-template
你可以渲染listLocal
,它会保持反应性(即,如果parentList
改变它会更新Task
组件)。您还可以listLocal
通过调用 setter(例如this.listLocal = newList
)来改变它,它会将更改发送给父级。
What's great about this pattern is that you can pass listLocal
to a child component of Task
(using v-model
), and changes from the child component will propagate to the top level component.
这种模式的优点在于您可以传递listLocal
给Task
(using v-model
) 的子组件,并且来自子组件的更改将传播到顶级组件。
For example, say we have a separate EditTask
component for doing some type of modification to the task data. By using the same v-model
and computed properties pattern we can pass listLocal
to the component (using v-model
):
例如,假设我们有一个单独的EditTask
组件来对任务数据进行某种类型的修改。通过使用相同的v-model
计算属性模式,我们可以传递listLocal
给组件(使用v-model
):
<script type="text/x-template" id="task-template">
<div>
<EditTask v-model="listLocal"></EditTask>
</div>
</script>
If EditTask
emits a change it will appropriately call set()
on listLocal
and thereby propagate the event to the top level. Similarly, the EditTask
component could also call other child components (such as form elements) using v-model
.
如果EditTask
发出改变它会适当地调用set()
上listLocal
,并由此传播事件到顶层。类似地,EditTask
组件也可以使用 调用其他子组件(例如表单元素)v-model
。
回答by sealla
Vue just warns you: you change the prop in the component, but when parent component re-renders, "list" will be overwritten and you lose all your changes. So it is dangerous to do so.
Vue 只是警告您:您更改了组件中的 prop,但是当父组件重新渲染时,“列表”将被覆盖,您将丢失所有更改。所以这样做是很危险的。
Use computed property instead like this:
像这样使用计算属性:
Vue.component('task', {
template: '#task-template',
props: ['list'],
computed: {
listJson: function(){
return JSON.parse(this.list);
}
}
});
回答by For the Name
If you're using Lodash, you can clone the prop before returning it. This pattern is helpful if you modify that prop on both the parent and child.
如果你使用 Lodash,你可以在返回它之前克隆 prop。如果您在父级和子级上修改该道具,则此模式很有用。
Let's say we have prop liston component grid.
假设我们在组件grid上有 prop列表。
In Parent Component
在父组件中
<grid :list.sync="list"></grid>
In Child Component
在子组件中
props: ['list'],
methods:{
doSomethingOnClick(entry){
let modifiedList = _.clone(this.list)
modifiedList = _.uniq(modifiedList) // Removes duplicates
this.$emit('update:list', modifiedList)
}
}
回答by edison xue
Props down, events up. That's Vue's Pattern. The point is that if you try to mutate props passing from a parent. It won't work and it just gets overwritten repeatedly by the parent component. Child component can only emit an event to notify parent component to do sth. If you don't like these restrict, you can use VUEX(actually this pattern will suck in complex components structure, you should use VUEX!)
道具下降,事件上升。这就是 Vue 的模式。关键是,如果你试图改变从父级传递过来的 props。它不起作用,它只会被父组件反复覆盖。子组件只能发出一个事件来通知父组件做某事。如果你不喜欢这些限制,你可以使用 VUEX(实际上这种模式会吸收复杂的组件结构,你应该使用 VUEX!)
回答by Potato Running
You should not change the props's value in child component.
If you really need to change it you can use .sync
.
Just like this
您不应更改子组件中道具的值。如果你真的需要改变它,你可以使用.sync
. 像这样
<your-component :list.sync="list"></your-component>
<your-component :list.sync="list"></your-component>
Vue.component('task', {
template: '#task-template',
props: ['list'],
created() {
this.$emit('update:list', JSON.parse(this.list))
}
});
new Vue({
el: '.container'
})
回答by burak buruk
According to the VueJs 2.0, you should not mutate a prop inside the component. They are only mutated by their parents. Therefore, you should define variables in data with different names and keep them updated by watching actual props. In case the list prop is changed by a parent, you can parse it and assign it to mutableList. Here is a complete solution.
根据 VueJs 2.0,你不应该改变组件内的 prop。他们只是被他们的父母变异了。因此,你应该在数据中定义不同名称的变量,并通过观察实际的道具来保持它们的更新。如果父项更改了列表属性,您可以解析它并将其分配给 mutableList。这是一个完整的解决方案。
Vue.component('task', {
template: ′<ul>
<li v-for="item in mutableList">
{{item.name}}
</li>
</ul>′,
props: ['list'],
data: function () {
return {
mutableList = JSON.parse(this.list);
}
},
watch:{
list: function(){
this.mutableList = JSON.parse(this.list);
}
}
});
It uses mutableList to render your template, thus you keep your list prop safe in the component.
它使用 mutableList 来呈现您的模板,因此您可以在组件中确保您的列表道具安全。
回答by Tango5614
do not change the props directly in components.if you need change it set a new property like this:
不要直接在组件中更改道具。如果您需要更改它,请设置一个新属性,如下所示:
data () {
return () {
listClone: this.list
}
}
And change the value of listClone.
并更改 listClone 的值。
回答by Vectrobyte
The answer is simple, you should break the direct prop mutation by assigning the value to some local component variables(could be data property, computed with getters, setters, or watchers).
答案很简单,您应该通过将值分配给一些局部组件变量(可以是数据属性,使用 getter、setter 或 watchers 计算)来打破直接 prop 突变。
Here's a simple solution using the watcher.
这是一个使用观察者的简单解决方案。
<template>
<input
v-model="input"
@input="updateInput"
@change="updateInput"
/>
</template>
<script>
export default {
props: {
value: {
type: String,
default: '',
},
},
data() {
return {
input: '',
};
},
watch: {
value: {
handler(after) {
this.input = after;
},
immediate: true,
},
},
methods: {
updateInput() {
this.$emit('input', this.input);
},
},
};
</script>
It's what I use to create any data input components and it works just fine. Any new data sent(v-model(ed)) from parent will be watched by the value watcher and is assigned to the input variable and once the input is received, we can catch that action and emit input to parent suggesting that data is input from the form element.
这是我用来创建任何数据输入组件的东西,它工作得很好。任何从父级发送(v-model(ed))的新数据都将被值观察者监视并分配给输入变量,一旦收到输入,我们就可以捕获该动作并向父级发出输入提示数据已输入从表单元素。
回答by ihsanberahim
I faced this issue as well. The warning gone after i use $on
and $emit
.
It's something like use $on
and $emit
recommended to sent data from child component to parent component.
我也遇到了这个问题。我使用$on
and后警告消失了$emit
。它类似于使用$on
并$emit
建议将数据从子组件发送到父组件。