状态管理学习(一)组件通信方式 、简易状态管理方案

组件间状态管理流程

Vue中最核心的功能,分别是数据驱动和组件化。

使用基于组件化的开发,可以提高开发效率,带来更好的可维护性。

每个组件中都有自己的:

  • state - 数据,也称为状态
    • 每个组件内部都可以管理自己的内部状态
  • view - 模板,也称为视图
    • 每个组件都有自己的视图,把状态绑定到视图上,呈现给用户
    • 当用户和视图交互的时候可能会更改状态
    • 当状态发生变化后,会自动更新到视图
  • actions - 方法,也称为行为
    • 更改状态的行为
new Vue({
  // state
  data () {
    return {
      count: 0
    }
  },
  // view
  template: `<div>{{ count }}</div>`,
  // actions
  methods: {
    increment () {
      this.count++
    }
  }
})

实际开发中,可能会需要在多个组件中共享状态。

状态管理

所谓的状态管理,就是通过状态集中管理和分发,解决多个组件共享状态的问题。

状态管理的组成:

  • state - 驱动应用的数据源
  • view - 以声明方式将 state 映射到视图
  • actions - 用户和视图交互,改变状态的方式

单向数据流

在这里插入图片描述

图中的箭头是数据的流向,数据的流向是单向的。

  • state(状态/数据)绑定到view(视图)展示给用户
  • 当用户和视图交互,通过actions更改state后
  • 再把更改后的state重新绑定到view

单向数据流程特别清晰,但是多个组件共享数据的时候会破坏这种简单的结构。

组件间通信方式回顾

再大多数场景下,组件并不是单独存在的。

多数情况下,组件都需要相互协作,共同构成一个复杂的业务功能。

常见的三种组件间通信方式

  • 父组件给子组件传值 - Props Down
    • 子组件中通过 props 接收父组件传递的数据
    • 父组件中给子组件通过相应属性传值
  • 子组件给父组件传值 - Event Up
    • 使用自定义事件 + $emit 方式
  • 不相关组件之间传值 - Event Bus
    • 同样使用自定义事件,但是不能通过子组件触发emit
    • 需要创建一个公共的实例( Event Bus)
    • 这个实例用于作为事件中介,或者事件中心
    • 调用它的 $on $emit,用来注册和触发事件

其他常见方式

可以通过以下属性获取组件中的成员,实现组件间通信:

  • $root - 根组件
    • 所有子组件都可以通过$root访问根实例上的成员
    • 所有的子组件都可以将这个实例作为一个全局 store 来访问或使用
      • 但这是不推荐的
  • $parent - 父组件
  • $children - 子组件
  • $refs - 访问子组件实例或子元素
    • 普通HTML标签 - 获取DOM
    • 组件标签 - 获取组件实例
  • 依赖注入:祖先组件向子孙组件传值
    • 使用:
      • provide - 祖先组件通过 provide 指定向下提供的数据或方法
      • inject - 子孙组件通过 inject 接收祖先组件提供的数据或方法,并注入到当前实例
    • 相比 props 传值的优点:
      • 祖先组件不需要知道哪些后代组件使用它提供的 property
      • 后代组件不需要知道被注入的 property 来自哪里
    • 同 props 一样:
      • property 是非响应式的
      • 相比状态集中管理,使用这种方式耦合起来的组件,难以重构

但是这些都是不被推荐的实现方式,容易导致数据管理的混乱。

只有在项目非常小,或开发自定义组件的时候才会使用到。

如果是开发大型项目还是推荐vuex来管理状态

简易的状态管理方案

简易的状态管理方案

如果多个组件之间需要共享状态/数据:

  • 多个视图依赖同一状态

    • 使用组件间传值的方式实现很麻烦,并且很难跟踪到数据的变化。出现问题很难定位。
  • 来自不同视图的行为需要变更同一状态

    • 使用父子组件的方式获取状态进行修改,或者通过事件机制改变同步状态的变化。
    • 但是这些方式很脆弱,通常会导致无法维护的代码。

为了解决这些问题,可以把不同组件之间的共享状态抽取出来,存储到一个全局对象中,并且将来使用的时候,要保证它是响应式的。

对象创建好之后,任何组件都可以获取或修改全局对象中的状态。

简单 store 模式 - 集中式状态管理

  • 使用全局唯一的 store 对象管理状态
  • 任意组件都可以导入 store 模块(store.js),使用/更改其中的状态
  • 约定:
    • 组件不允许直接修改 store 对象的 state 属性
    • 如果想要改变 state,需要调用 action 来改变 store 中的状态
  • 约定的好处:
    • 可以记录 store 中所有状态的变更
    • 从而实现高级的调试功能,例如:time-travel 时光旅行和历史回滚

这里使用的 store 就类似 vuex 中的仓库。

// store
export default {
  // debug 方便调试
  debug: true,

  // 状态:用于存储数据
  state: {
    user: {
      name: 'xiaoming',
      age: 18,
      sex: '男'
    }
  },

  // action:用于用户和视图交互的时更改数据
  setUserNameAction (name) {
    if (this.debug) {
      console.log('setUserNameAction triggered:', name)

      this.state.user.name = name
    }
  }
}

// compa.vue
<template>
  <div>
    <h1>componentA</h1>
    user name: {{ sharedState.user.name }}
    <button @click="change">Change Info</button>
  </div>
</template>

<script>
import store from './store'
export default {
  data () {
    return {
      privateState: {},
      sharedState: store.state
    }
  },
  methods: {
    change () {
      store.setUserNameAction('componentA')
    }
  }
}
</script>

<style></style>

// compb.vue
<template>
  <div>
    <h1>componentB</h1>
    user name: {{ sharedState.user.name }}
    <button @click="change">Change Info</button>
  </div>
</template>

<script>
import store from './store'
export default {
  data () {
    return {
      privateState: {},
      sharedState: store.state
    }
  },
  methods: {
    change () {
      store.setUserNameAction('componentB')
    }
  }
}
</script>

<style></style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值