I started the https://laracasts.com/series/learning-vue-step-by-step series. I stopped the Vue, Laravel and AJAX classes with the following error:
vue.js:2574 [Vue warn]: Avoid changing props directly as the value will be overwritten whenever the parent component re-renders. Instead, use data or computed properties based on the value of the prop. Changing props: "list" (found in component)
I have this code in main.js
Vue.component('task', { template: '#task-template', props: ['list'], created() { this.list = JSON.parse(this.list); } }); new Vue({ el: '.container' })
I know the problem is in created() when I override the list property, but I'm new to Vue so I have absolutely no idea how to fix it. Does anyone know how (and please explain why) to fix it?
Vue modes are props
down, events
up. Sounds simple, but it's easy to forget when writing custom components.
Starting with Vue 2.2.0, you can use v -model (with computed properties). I find this combination creates a simple, clean, and consistent interface between components:
props
passed to the component remains responsive (i.e., it will not be cloned, nor will a watch
function be required to update the local copy when a change is detected).
Computed properties allow setters and getters to be defined individually. This allows the Task
component to be rewritten as follows:
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
model property defines the associated prop
and v-model
, and which event will be emitted when changed. You can then call this component from the parent component like this:
<Task v-model="parentList"></Task>
listLocal
Computed properties provide a simple getter and setter interface within the component (think of them as private variables). In #task-template
you can render listLocal
and it will remain reactive (i.e. if parentList
changes, it will update Task component). You can also change the
listLocal
by calling a setter (e.g. this.listLocal = newList
), which will send the changes to the parent.
The advantage of this pattern is that you can pass a listLocal
to a child component of Task
(using v-model
) and make changes from the child component The content will be propagated to the top-level component.
For example, suppose we have a separate EditTask
component that makes some type of modification to task data. By using the same v-model
and computed property pattern, we can pass listLocal
to the component (using v-model
):
<script type="text/x-template" id="task-template"> <div> <EditTask v-model="listLocal"></EditTask> </div> </script>
If the EditTask
emits a change, it will appropriately call set()
on the listLocal
, thereby propagating the event to the top level. Similarly, the EditTask
component can also use v-model
to call other sub-components (such as form elements).
This has to do with the fact that Changing props locally is considered an anti-pattern in Vue 2
If you want to change prop locally, what you should do now is declare a field in data
using props code> value as its initial value, and then change the copy :
Vue.component('task', { template: '#task-template', props: ['list'], data: function () { return { mutableList: JSON.parse(this.list); } } });
You can read more about it on Vue.js Official Guide
Note 1: Please note that you should not not for prop
and data
使用相同的名稱>,Right now:
data: function () { return { list: JSON.parse(this.list) } } // WRONG!!
Note 2: Since I think there is some confusion about
props and reactivity, I suggest you take a look at this Thread