Vuex 状态管理实践城市选择页

695 阅读3分钟

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

状态管理模式

一个状态自管理应用包含以下几个部分:

state,驱动应用的数据源;

view,以声明方式将 state 映射到视图;

actions,响应在 view 上的用户输入导致的状态变化。

当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:

多个视图依赖于同一状态。

不同视图需要变更同一状态。

所以状态管理模式就是把共享的状态提取出来,在一个全局的地方进行统一管理。不管组件在哪,都能触发行为、获取状态,提高了代码维护性。

原理简单理解

Vuex 实现了一个单向数据流,全局管理 state 状态树,组件通过派发 Dispatch 一个 action,action 也是无法直接修改State的,还是需要通过 Mutation来修改State的数据。action 进行 commit 并调用 Mutations 方法来更改 state,Mutation同时提供了订阅者模式供组件调用获取State数据的更新。最后根据 state 的变化触发视图的更新。

Vue Components:Vue组件。

dispatch:是唯一能执行action的方法。

actions:由组件 dispatch 触发。然后由commit()来触发mutation的调用 , 更新 state。

commit:状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。

mutations:状态改变操作方法,由actions中的commit('mutation 名称')来触发。该方法只能进行同步操作,且方法名只能全局唯一。

state:页面状态管理容器对象。

实践 - 城市选择

实现一个常见的城市选择页面。包含首页和城市选择页。

新建一个 IndexPage.vue

// IndexPage.vue
 
<template>
  <div>{{city}}</div>
</template>

<script>
  import { mapState} from 'vuex'

  export default {
    name: "IndexPage",
    computed: {
      ...mapState(['city'])
    }
  }
</script>

新建一个 CityPage.vue

// CityPage.vue

<template>
<div>
  <p>当前城市:{{city}}</p>
  <div v-for="item of ['北京','上海','广州']" :key="item">
    <button @click="handleChangeCity(item)"
    >{{item}}
    </button>
  </div>
</div>
</template>

<script>
  import { mapState ,mapMutations  } from 'vuex'

  export default {
    name: "CityPage",
    computed: {
      ...mapState(['city'])
    },
    methods: {
      ...mapMutations(['changeCity']),
      handleChangeCity (city) {
        this.changeCity(city)
      },
    },
  }
</script>

在 App.vue 中加入这两个页面。

//  App.vue

<template>
  <div>
    <IndexPage/>
    -----------
    <CityPage/>
  </div>
</template>

<script>
import IndexPage from './pages/IndexPage'
import CityPage from './pages/CityPage'

export default {
  name: 'App',
  components: {
    IndexPage,
    CityPage
  }
}
</script>

接下来重点来了,src 里 新建一个 store 文件夹 (如果使用脚手架搭建的就已经有这个文件夹了)。

store 文件夹下新建一个 index.js ,别忘了注入到 main.js。

//  index.js

import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
import actions from './actions'

Vue.use(Vuex)

export default new Vuex.Store({
  state,
  actions,
  mutations
})

新建一个 state.js

//  state.js

let defaultCity = '全国'

try {
  if (localStorage.city) {
    defaultCity = localStorage.city
  }
} catch (e) {
}

export default {
  city: defaultCity
}

新建一个 actions.js

// actions.js

export default {
  changeCity (context, city) {
    context.commit('changeCity', city)
  }
}

新建一个 mutations.js

// mutations.js

export default {
  changeCity (state, city) {
    state.city = city
    try {
      localStorage.city = city
    } catch (e) {
    }
  }
}

完成后如下图所示。选择新的城市,首页和城市选择页里的 city 会同步更新。