DEV Community

Olayemi Elsie
Olayemi Elsie

Posted on

Component Composition & State Flow

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)