Vue NativeVue Native
Guide
Components
Composables
Navigation
  • iOS
  • Android
  • macOS
GitHub
Guide
Components
Composables
Navigation
  • iOS
  • Android
  • macOS
GitHub
  • Getting Started

    • Introduction
    • Installation
    • Your First App
    • Project Structure
  • Core Concepts

    • Components
    • Styling
    • Navigation
    • Native Modules
    • Native Code Blocks
    • Hot Reload
  • Advanced

    • Error Handling
    • Accessibility
    • TypeScript
    • Performance
    • Shared Element Transitions
    • Testing
    • Security
    • Debugging
    • Teleport
    • Forms and v-model
  • Integration Guides

    • State Management
    • Deep Linking & Universal Links
    • State Persistence
    • Push Notifications
    • Error Reporting & Monitoring
  • Tooling

    • Managed Workflow
    • VS Code Extension
    • Neovim Plugin
  • Building & Releasing

    • Building for Release
    • Deployment & App Store Submission
  • Reference

    • Migration & Upgrade Guide
    • Known Limitations & Platform Differences
    • Troubleshooting

State Management

Local State

For single-component state, Vue's Composition API is all you need:

import { ref, reactive, computed } from '@thelacanians/vue-native-runtime'

const count = ref(0)
const user = reactive({ name: 'Alice', email: 'alice@example.com' })
const displayName = computed(() => user.name.toUpperCase())

Sharing State Across Components

provide / inject

For state shared within a component subtree (parent and all descendants), use provide and inject:

// Parent component
import { provide, ref } from '@thelacanians/vue-native-runtime'

const user = ref({ name: 'Alice', loggedIn: true })
provide('user', user)
// Any descendant component
import { inject } from '@thelacanians/vue-native-runtime'

const user = inject('user')

Composable Pattern

For reusable state that multiple components share, create a composable with module-level state:

// composables/useAuth.ts
import { ref, readonly } from '@thelacanians/vue-native-runtime'

const user = ref<{ name: string; token: string } | null>(null)
const isLoggedIn = ref(false)

export function useAuth() {
  async function login(email: string, password: string) {
    // Call your API...
    user.value = { name: 'Alice', token: 'abc123' }
    isLoggedIn.value = true
  }

  function logout() {
    user.value = null
    isLoggedIn.value = false
  }

  return {
    user: readonly(user),
    isLoggedIn: readonly(isLoggedIn),
    login,
    logout,
  }
}
<!-- Any component -->
<script setup>
import { useAuth } from '../composables/useAuth'
const { user, isLoggedIn, logout } = useAuth()
</script>

This pattern works because ES module state is shared across all imports — every component that calls useAuth() gets the same user and isLoggedIn refs.

Pinia

Pinia is the official Vue state management library and works with Vue Native.

Setup

Install Pinia in your project:

bun add pinia

Register the Pinia plugin in your entry point:

// app/main.ts
import { createApp } from '@thelacanians/vue-native-runtime'
import { createPinia } from 'pinia'
import App from './App.vue'

const app = createApp(App)
app.use(createPinia())
app.start()

Define a Store

// stores/counter.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const doubleCount = computed(() => count.value * 2)

  function increment() {
    count.value++
  }

  function decrement() {
    count.value--
  }

  return { count, doubleCount, increment, decrement }
})

Use in Components

<script setup>
import { useCounterStore } from '../stores/counter'
import { storeToRefs } from 'pinia'

const store = useCounterStore()
const { count, doubleCount } = storeToRefs(store)
</script>

<template>
  <VView :style="{ flex: 1, alignItems: 'center', justifyContent: 'center' }">
    <VText :style="{ fontSize: 48 }">{{ count }}</VText>
    <VText :style="{ fontSize: 16, color: '#8E8E93' }">Double: {{ doubleCount }}</VText>
    <VButton :onPress="store.increment">
      <VText>Increment</VText>
    </VButton>
    <VButton :onPress="store.decrement">
      <VText>Decrement</VText>
    </VButton>
  </VView>
</template>

Why It Works

Vue Native's Vite plugin aliases vue → @thelacanians/vue-native-runtime, which re-exports all of @vue/runtime-core (including effectScope, inject, provide, markRaw, etc.). Since Pinia imports from vue, it receives the same Vue instance that the renderer uses. Vite's bundler deduplicates the dependency, ensuring a single copy.

Persisting Store State

Combine Pinia with useAsyncStorage to persist state across app restarts:

// stores/settings.ts
import { defineStore } from 'pinia'
import { ref, watch } from 'vue'
import { useAsyncStorage } from '@thelacanians/vue-native-runtime'

export const useSettingsStore = defineStore('settings', () => {
  const { getItem, setItem } = useAsyncStorage()
  const theme = ref<'light' | 'dark'>('light')
  const fontSize = ref(16)

  // Load persisted state on store creation
  async function hydrate() {
    const saved = await getItem('settings')
    if (saved) {
      const data = JSON.parse(saved)
      theme.value = data.theme ?? 'light'
      fontSize.value = data.fontSize ?? 16
    }
  }

  // Persist on change
  watch([theme, fontSize], () => {
    setItem('settings', JSON.stringify({ theme: theme.value, fontSize: fontSize.value }))
  })

  hydrate()

  return { theme, fontSize }
})

Recommendations

ComplexitySolution
Single componentref(), reactive()
Parent → children sharingprovide() / inject()
Few cross-screen values (auth, theme)Composable with module-level state
Complex app with many storesPinia

For most Vue Native apps, the composable pattern is sufficient and has zero dependencies. Use Pinia when you need devtools support, store composition, or are already familiar with it from web Vue development.

Hot Reload

Hot reload resets all JavaScript state, including Pinia stores and composable module state. Use useAsyncStorage for critical state you need to survive reloads during development.

Edit this page
Last Updated: 2/28/26, 11:24 PM
Contributors: Abdul Hamid, Claude Opus 4.6
Next
Deep Linking & Universal Links