Props
What Are Props?
Props are properties coming from the parent component. These properties are stored in an object that, for most of the time, is being called props
.
For example, if you declare your props in a component like this:
const props = defineProps<{
name: string
age: number
}>()
Then in the parent you could pass values to it like this:
<template>
<ChildComponent
:name="myName"
:age="myAge"
/>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
const myName = ref('hello')
const myAge = ref(5)
</script>
Shallow Reactive and Shallow Readonly
Here's an interesting fact: the props
object is actually a non-strict shallow reactive proxy with shallow readonly constraint!
What Is Shallow Reactive?
Shallow reactive means in an object, only the root-level properties are reactive; properties deeper than that are not reactive. We can use the shallowReactive()
function to create a shallow reactive proxy, for example:
import { shallowReactive } from 'vue'
const user = shallowReactive({
name: 'hello',
child: {
age: 5,
},
})
In this example, user
is declared as a shallow reactive proxy, which means:
- Mutating
user.name
will cause the component to re-render. - Replacing
user.child
with any other value will cause the component to re-render. - Mutating
user.child.age
will not cause the component to re-render.
However, if user.child
has been a reactive proxy since the beginning, mutating user.child.age
would also cause the component to re-render, because all shallowReactive()
does is making root-level properties reactive; it never "de-reactive" any reactive properties. For example:
import { reactive, shallowReactive } from 'vue'
const user = shallowReactive({
name: 'hello',
child: reactive({
age: 5,
}),
})
In this example:
- Mutating
user.name
will cause the component to re-render, becauseuser
is a shallow reactive proxy. - Replacing
user.child
with any other value will cause the component to re-render, becauseuser
is a shallow reactive proxy. - Mutating
user.child.age
will also cause the component to re-render, becauseuser.child
is a reactive proxy.
Unlike reactive()
, shallowReactive()
does not go through the unwrap process while making a proxy, so the return type of shallowReactive()
is guaranteed to be the same as the type of argument.
What Is Shallow Readonly?
Shallow readonly means in an object, only the root-level properties are readonly; properties deeper than that are not readonly. We can use the shallowReadonly()
function to create a shallow readonly object, for example:
import { shallowReadonly } from 'vue'
const user = shallowReadonly({
name: 'hello',
child: {
age: 5,
},
})
In this example, user
is declared as a shallow readonly object, which means:
- We cannot mutate
user.name
. - We cannot replace
user.child
with any other value. - We can mutate
user.child.age
.
To sum it up, you can think of props
as a reactive proxy made by shallowReactive()
and shallowReadonly()
; it's just that all property values are coming from parent component.
import { shallowReactive, shallowReadonly } from 'vue'
const props =
shallowReadonly(
shallowReactive({
// ...
})
)
You should always avoid directly mutating props in child components so that the data flow of your components stays one-way (from top to bottom). If you have to mutate props in child components, you should use events
. The main concept is, parent component is the only one that's allowed to mutate those values; all children do is to "trigger" those changes.
The Reactivity of Props
Have you ever been in a situation that for some reason, "some" properties in your props are just not reactive?
For most of the time, that means you've accidentally broke the reactivity of props. Since props
is a shallow reactive proxy, you can just treat it like a reactive proxy. Check here for solutions!