Vue2, vue3 components pass value, reference type, how to deal with object array
Excerpt
All props form a single downward binding between their parent and child props: updates to the parent prop flow down to the child components, but not the other way around. This will prevent accidental changes from child components to parent...
The following component pass-by-value refers to 引用类型
(array or object) pass-by-value.
The principles of vue2 and vue3 are the same, if you have any questions, please leave a message.
Prepare: One-way data flow
All props form a relationship between their parent and child props 单向下行绑定
: updates to parent props flow down to child components, but not the other way around. This prevents accidental changes to the parent component's state from child components, which can make your app's data flow difficult to understand.
In addition, every time the parent component changes, all props in the child component will be refreshed with the latest values. This means you should not change props inside a child component. If you do this, Vue will issue a warning in the browser's console.
- This prop is used to pass an initial value; the child component then expects to use it as a local prop data. Define a local data property and use this prop as its initial value
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
- This prop is passed in as a raw value and needs to be converted. Use the value of this prop to define a
计算属性
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
Note that objects and arrays are passed in by reference in JavaScript, so for an array or object type prop, in
子组件中改变变更这个对象或数组本身将会影响到父组件的状态
.
question
prop transfers application type data (objects, arrays), and changes in subcomponents will directly change the parent component
Parent component App.vue
<template>
<div id="app">
<child :initialValue="valueEmit">
</child>
</div>
</template>
<script>
import childEmit from './components/child.vue'
export default {
data () {
return {
valueEmit: {
cat: 2}
}
},
components: {
child
}
}
</script>
Child component components/child.vue
<template>
<div class="child-container">
<p>
<label>child:</label>
<input type="text" v-model="value.cat" />
</p>
</div>
</template>
<script>
export default {
name: 'child',
props: {
initialValue: Object
},
data () {
return {
value: this.initialValue
}
}
}
</script>
Question 2
To change the child component without affecting the parent component, you can make a deep copy of the reference type data, but the parent component data change will not trigger the child component to respond. Modify the child component
, child component components/child.vue
export default {
name: 'child',
props: {
initialValue: Object
},
data () {
return {
valueEmit: JSON.parse(JSON.stringify(this.initialValue))
}
}
}
Summarize
In our development process, we generally encounter the following three situations:
纯展示
Use parent component properties directly without side effects!
<template>
<div>
{
{
parentObj.value}}
</div>
</template>
<script>
export default {
name: 'child',
props: {
parentObj: Object
}
}
</script>
只子组件内部修改
, the parent component will not modify (that is, the parent component only initializes) the new data declared in the child component data, and the reference can be cut off byObject.assign()
orJSON.parse(JSON.stringify())
.
<template>
<div>
<input type="text" v-model="childObj.value">
</div>
</template>
<script>
export default {
name: 'child',
props: {
parentObj: Object
},
data () {
return {
childObj: Object.assign({
}, this.parentObj)
}
}
}
</script>
父子组件都会修改
Processing by computed or watch
<template>
<div>
<input type="text" v-model="childObj.value">
</div>
</template>
<script>
export default {
name: 'child',
props: {
parentObj: Object
},
computed: {
childObj () {
return Object.assign({
}, this.parentObj)
}
}
}
</script>
或者 watch 方式
export default {
name: 'child',
props: {
parentObj: Object
},
data () {
return {
childObj: {
}
}
},
watch: {
parentObj: {
handler (val, oldVal) {
if (val) {
this.childObj = Object.assign({
}, this.parentObj)
}
},
deep: true,
immediate: true
}
}
}
- About the difference between watch and computed: the correct way to use vue computed