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.namewill cause the component to re-render. - Replacing
user.childwith any other value will cause the component to re-render. - Mutating
user.child.agewill 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.namewill cause the component to re-render, becauseuseris a shallow reactive proxy. - Replacing
user.childwith any other value will cause the component to re-render, becauseuseris a shallow reactive proxy. - Mutating
user.child.agewill also cause the component to re-render, becauseuser.childis 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.childwith 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!