Component composition is how we build complex UIs by combining smaller, reusable components.
Instead of one big component, we break it into smaller pieces.
These smaller components can be nested, reused, and organized to create the full UI.
State flow is how data moves between components in an application.
Parent → Child: via props
Child → Parent: via events ($emit)
Shared / global state: for siblings or distant components (using reactive stores or composables)
Key idea: State flow ensures all components stay in sync and respond correctly when data changes.
Props
Props are communication between Parent & Child Component. (short for “properties”)
A parent component sends data to a child component through props. A child component cannot send data directly to its parent. Instead, the parent passes a function as a prop to the child, and the child calls that function to send data back up
Passing props from Parent → Child
Passing props from Child → Parent Component
Example
Parent Component
Child Component
const props = defineProps({
title: String
})
Accessing prop in the template
{{ title }}
Accessing prop in script
const props = defineProps({
title: {
type: String,
default: "No title specified"
}})
Composables
Composables are the Vue3 equivalent of mixins in the options API.
They allow us to extract reusable logic (state and functions) into a separate file so we can reuse it in different components.
Instead of repeating code in many components, we write the logic once and import it where needed.
Creating a Composable
A composable is a function that contains reactive state and methods are returned what we want to use and then we export it.
Note:
It is important to name composable files starting with "use" e.g useDarkMode.js and to use camelCase for the file name.
Example:
useCounter.js
import { ref } from 'vue'
export default function useCounter() {
const count = ref(0)
function increment() {
count.value++
}
function decrement() {
count.value--
}
return { count, increment, decrement }
}
ref(0) → creates reactive state
increment() and decrement() → functions that modify state
return {} → exposes what we want to use in components
export → allows us to reuse it anywhere.
The return exposes the composable’s state and functions as an object.
When you import the composable in the vue component and destructure it, the component can see and use those state values and functions directly.
useCounter.vue
<script>
Import useCounter.js from ......
useCounter.vue
// object destructuring gives you access
const { count, increment, decrement } = useCounter()
Events
Events are how a child component communicates with its parent.
A custom event is like a special message that the child sends to the parent to notify it about something.
Dynamic Component
A dynamic component allows the switch between different components at runtime without manually nesting them all in the template.
Instead of writing all possible components in the template, it can render one component at a time based on a variable.
How it works
<component :is="currentComponent"></component>
:is → binds to a variable that holds the component to be rendered.
currentComponent → can be a component object.
When currentComponent changes, Vue automatically renders the new component.
Example
Example: Light Mode / Dark Mode
<script setup>
import LightMode from './LightMode.vue'import DarkMode from './DarkMode.vue'
import { ref } from 'vue'
const currentComponent = ref('LightMode')
function toggleMode() {
currentComponent.value = currentComponent.value === 'LightMode' ? 'DarkMode' : 'LightMode'}
Toggle Mode
currentComponent determines which component is shown.
Clicking the button switches between LightMode and DarkMode.
replaces the need to manually nest and
State Management
State management is how data is shared and kept in sync between multiple components.
- Use props and events to pass data between a parent and child.
- Use global/reactive state when siblings or multiple components need the same data. ' Example:
// store.js
import { ref } from 'vue'
export const userName = ref('Olayemi')
import { userName } from './store.js'
function changeName() {
userName.value = 'Olusegun' }
{{ userName }}
Change Name
import { userName } from './store.js'
{{ userName }}
Changing the value in one component will update it everywhere that uses the same store.
Notes:
- The default value is shown if the prop is not specified in the parent component.
- defineProps() – No need to import it.Props from Vue docs are automatically available.
Events
A way a Child Component communicates with Parent Component.
A custom event is like a special message that a child component sends to its parent saying something.
Example (Child)
Dynamic Component
Switches between different components dynamically.
Example:
Let’s say we have a Light Mode and Dark Mode.
You want to click on a button to switch between Light & Dark.
This can be achieved by dynamic component.
is used instead of nesting components directly.
Composable
The equivalent of mixin.
It allows us to extract reusable logic & methods and keep them in a separate template so we can reuse them.
Creating a Composable
We need to create a function for it & export default function.
Example:
export default function useCounter() { const count = ref(0) function increment() { count.value++ } return { count, increment }}
Inside Vue file, we need to import and use it.
import useCounter from './useCounter'const { count, increment } = useCounter()
NB
When importing a module:
import xxx from '...'
When importing a specific named export:
import { xxx } from '...'
Key Points
Use dynamic v-if if we have many components.
Use composables to make use of reusable logic in Vue.
Top comments (0)