用响应式 API 做简单状态管理

文章目录

  • 用响应式 API 做简单状态管理
    • 1. 概念
      • 1.1 状态管理
      • 1.2 多个组件共享一个共同的状态
    • 2. 响应式实例---用响应式 API 做简单状态管理

用响应式 API 做简单状态管理

1. 概念

1.1 状态管理

理论上来说,每一个 Vue 组件实例都已经在“管理”它自己的响应式状态了。以一个简单的计数器组件为例:

<script setup>
import { ref } from 'vue'
 
// 状态
const count = ref(0)
 
// 动作
function increment() {
  count.value++
}
</script>
 
<!-- 视图 -->
<template>{{ count }}</template>

它是一个独立的单元,由以下几个部分组成:

  • 状态:驱动整个应用的数据源;

  • 视图:对状态的一种声明式映射;

  • 交互:状态根据用户在视图中的输入而作出相应变更的可能方式。

“单向数据流”概念的简单图示:

用响应式 API 做简单状态管理_第1张图片

1.2 多个组件共享一个共同的状态

当有多个组件共享一个共同的状态时:

  • 多个视图可能都依赖于同一份状态。

  • 来自不同视图的交互也可能需要更改同一份状态。

    • 对于情景 1,一个可行的办法是将共享状态“提升”到共同的祖先组件上去,再通过 props 传递下来。然而在深层次的组件树结构中这么做的话,很快就会使得代码变得繁琐冗长。这会导致另一个问题:Prop 逐级透传问题。

    • 对于情景 2,我们经常发现自己会直接通过模板引用获取父/子实例,或者通过触发的事件尝试改变和同步多个状态的副本。但这些模式的健壮性都不甚理想,很容易就会导致代码难以维护。

一个更简单直接的解决方案是 抽取出组件间的共享状态放在一个全局单例中来管理。这样组件树就变成了一个大的“视图”,而任何位置上的组件都可以访问其中的状态或触发动作。

2. 响应式实例—用响应式 API 做简单状态管理

  • 在选项式 API 中,响应式数据是用 data() 选项声明的。在内部,data() 的返回值对象会通过 reactive() 这个公开的 API 函数转为响应式。

    如果有一部分状态需要在多个组件实例间共享,你可以使用 reactive() 来创建一个响应式对象,并将它导入到多个组件中

    在 store 上定义方法,实现自增increment(),可以确保改变状态的逻辑像状态本身一样集中,不会被任何组件任意改变的全局状态
    用响应式 API 做简单状态管理_第2张图片

    // 用响应式 API 做简单状态管理
    import {reactive} from "vue";
    // 使用 reactive() 来创建一个响应式对象,使其可以导入到多个组件中
    // 在store中暴露count初始值为0
    export const store = reactive({
        count: 0,
        increment() {
            this.count++
        }
    })
    
  • 每当 状态 对象被更改时,组件a与 组件b都会自动更新它们的视图。这样就有了单一的数据源。也意味着任意一个导入了 store 的组件都可以随意修改它的状态。
    ComponentA.vue:用响应式 API 做简单状态管理_第3张图片

    <script>
    //导入count初始值0
    import {store} from "@/store";
    export default {
      name: "ComponentA",
      // store动态
      data() {
        return {
          store
        }
      }
    }
    </script>
    
    <template>
      <div>
        <button @click="store.increment()">
          From A: {{ store.count }}
        </button>
      </div>
    </template>
    
    <style scoped>
    
    </style>
    

    ComponentB.vue:
    用响应式 API 做简单状态管理_第4张图片

    <script>
    //导入count初始值0
    import {store} from "@/store";
    export default {
      name: "ComponentB",
      data() {
        return {
          store
        }
      }
    }
    </script>
    
    <template>
      <div>
        <button @click="store.increment()">
          From B: {{ store.count }}
        </button>
      </div>
    </template>
    
    <style scoped>
    
    </style>
    

    App.vue:
    用响应式 API 做简单状态管理_第5张图片

    <template>
      <div>
    <!--    <test></test>-->
    <!--    <calendar></calendar>-->
        <component-a></component-a>
        <component-b></component-b>
      </div>
    </template>
    
    <script>
    import Test from "@/components/Test.vue";
    import Calendar from "@/components/calendar.vue";
    import ComponentA from "@/components/ComponentA.vue";
    import ComponentB from "@/components/ComponentB.vue";
    
    
    export default {
      name: 'App',
      components: {
        ComponentB,
        ComponentA,
        // Calendar,
        // Test
      }
    }
    </script>
    
    <style lang="scss" scoped>
    
    </style>
    
  • 页面效果:点击会响应式实现自增,同增同减,这样也能实现数据同步,不会出现任何组件任意改变的全局状态,确保改变状态的逻辑像状态本身一样集中

    用响应式 API 做简单状态管理_第6张图片用响应式 API 做简单状态管理_第7张图片

Vue 的响应性系统与组件层是解耦的,这使得它非常灵活。

你可能感兴趣的:(javascript,前端,开发语言)