Skip to content

全局状态 vs 局部状态

在 Vue 应用开发中,合理划分全局状态和局部状态是架构设计的关键决策。以下是两者的深度对比和最佳实践指南。

核心概念对比

维度全局状态局部状态
作用范围整个应用共享单个组件或少数紧密耦合组件
生命周期应用生命周期组件生命周期
典型场景用户信息、主题、权限表单数据、UI控制状态
管理工具Pinia/Vuexref/reactive/组件props
可预测性需严格管理变更变更影响范围小

全局状态详解

定义与特点

全局状态是多个无关组件需要访问和修改的数据,具有以下特征:

  • 跨路由/组件共享
  • 需要持久化或同步
  • 有明确的变更规则

典型使用场景

  • 用户认证信息(token、用户资料)
  • 应用主题/语言偏好
  • 全局通知/弹窗状态
  • 购物车数据(电商场景)
  • 多组件共享的API数据

实现方案

方案1:Pinia(推荐)

javascript
// stores/user.js
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    token: localStorage.getItem('token') || '',
    profile: null
  }),
  actions: {
    async login(credentials) {
      const res = await api.login(credentials)
      this.token = res.token
      this.profile = res.user
      localStorage.setItem('token', res.token)
    }
  }
})

方案2:Vuex

javascript
// store/modules/user.js
export default {
  namespaced: true,
  state: () => ({
    token: ''
  }),
  mutations: {
    SET_TOKEN(state, token) {
      state.token = token
    }
  }
}

管理原则

  1. 单一数据源:每个业务域只有一个store
  2. 不可变更新:通过actions修改状态(Pinia允许直接修改但不推荐)
  3. 类型安全:为全局状态定义TypeScript接口
  4. 持久化策略:关键状态需配合localStorage/IndexedDB

局部状态详解

定义与特点

局部状态是组件自身或父子组件间使用的数据,特点包括:

  • 影响范围有限
  • 随组件销毁而释放
  • 修改无需复杂流程

典型使用场景

  • 表单输入框的值
  • 组件展开/折叠状态
  • 对话框可见性控制
  • 列表排序/筛选条件
  • 动画过渡状态

实现方案

方案1:组合式API(推荐)

vue
<script setup>
import { ref } from 'vue'

// 局部状态
const searchQuery = ref('')
const isDropdownOpen = ref(false)

function toggleDropdown() {
  isDropdownOpen.value = !isDropdownOpen.value
}
</script>

方案2:选项式API

javascript
export default {
  data() {
    return {
      searchQuery: '',
      isDropdownOpen: false
    }
  },
  methods: {
    toggleDropdown() {
      this.isDropdownOpen = !this.isDropdownOpen
    }
  }
}

管理原则

  1. 就近原则:状态定义在最近共同祖先组件
  2. 最小暴露:只向子组件暴露必要状态
  3. 响应式优化:复杂状态使用shallowRef/shallowReactive
  4. 清理副作用:onUnmounted中取消事件监听

决策流程图

混合使用模式

全局状态派生局部状态

vue
<script setup>
import { useUserStore } from '@/stores/user'
import { computed } from 'vue'

const userStore = useUserStore()

// 从全局状态派生局部状态
const username = computed(() => userStore.profile?.name || '游客')
</script>

局部状态同步到全局

javascript
// 在组件中
const formData = ref({})
const userStore = useUserStore()

const submit = () => {
  // 将局部状态提交到全局
  userStore.updateProfile(formData.value)
}

常见误区与解决方案

误区问题解决方案
过度全局化组件复用困难严格评估状态使用范围
深层嵌套props"Prop Drilling"问题使用provide/inject
直接修改全局状态难以追踪变更强制通过actions修改
忽略状态清理内存泄漏使用onUnmounted生命周期

性能优化技巧

全局状态优化

  • 使用computed延迟计算
  • 大对象分片存储(如分页数据)
  • 防抖高频更新操作

局部状态优化

  • 非响应式数据使用markRaw
  • 列表项使用v-memo
  • 高频更新使用shallowRef

实战案例

全局主题切换

javascript
// stores/theme.js
export const useThemeStore = defineStore('theme', {
  state: () => ({
    mode: 'light',
    colors: { primary: '#409EFF' }
  }),
  actions: {
    toggleMode() {
      this.mode = this.mode === 'light' ? 'dark' : 'light'
      document.body.className = this.mode
    }
  }
})

局部表单状态

vue
<script setup>
const form = reactive({
  name: '',
  age: null,
  agree: false
})

const validate = () => {
  if (!form.name) alert('姓名必填')
}
</script>

<template>
  <input v-model="form.name">
  <button @click="validate">提交</button>
</template>
编程洪同学服务平台是一个广泛收集编程相关内容和资源,旨在满足编程爱好者和专业开发人员的需求的网站。无论您是初学者还是经验丰富的开发者,都可以在这里找到有用的信息和资料,我们将助您提升编程技能和知识。
专业开发
高端定制
售后无忧
站内资源均为本站制作或收集于互联网等平台,如有侵权,请第一时间联系本站,敬请谅解!本站资源仅限于学习与参考,严禁用于各种非法活动,否则后果自行负责,本站概不承担!