[关闭]
@lizlalala 2017-01-10T09:20:13.000000Z 字数 3393 阅读 1125

vue学习-vuex

vuex vue的坑


  1. state
    Vuex提供了机制,使得设置 store选项(启用Vue.use(Vuex))会将 store 从根组件『注入』到每一个子组件中。

    1. const app = new Vue({
    2. el: '#app',
    3. // 使用 "store" 选项后,可以注册 store 对象。将会把 store 实例注入到所有子组件。
    4. store,
    5. components: { Counter },
    6. template: `
    7. <div class="app">
    8. <counter></counter>
    9. </div>
    10. `
    11. })

    子组件中可以通过this.$store.state.someprop访问

    mapState:

    1. computed: mapState({
    2. count: state => state.count,
    3. countAlias: 'count',
    4. 'count',
    5. countPlusLocalState (state) {
    6. return state.count + this.localCount
    7. }
    8. })
    9. 或者用对象扩展方法将mapState作为computed的部分
    10. computed:{
    11. test1(){..},
    12. ...mapState({})
    13. }
  2. getters
    类似于store的计算属性函数,接受state作为第一个参数

    1. const store = new Vuex.Store({
    2. state: {
    3. },
    4. getters: {
    5. doneTodos: state => ...
    6. }
    7. })

    组件中用this.$store.getters.blah访问

  3. Mutations

    • 遵循响应式规则,即预先初始化,需要增加属性时,用set或者新对象来替换旧对象。
    • 常量命名Mutation,统一管理
    • 同步函数
    • 每个mutation都有一个type和一个回调函数。回调函数的参数为state,也接受payload
  4. actions

    • 不改变state,只commit,类似于emit一个事件。
    • 可以处理异步操作,弥补mutation只能是同步函数的问题。
    • 处理参数接受context为参数。context包括与store实例相同的方法和属性。可以用es6参数解构来获得里面的commit等

更新1
vuex重构了todo,见github


更新2
1. 需要注意的是,整个操作中只通过在store里面提交mutations来实现数据的更改,(便于用dev-统一tool去统一跟踪)。
2. 总的来说,vuex解决的是用纯数据交互的方式来处理原本属于组件间(sibling组件)的通信,有人会说那我用event也可以做到通信啊,但是当组件创建、销毁时,这些状态也随之变动,因此需要有一个独立于组件的状态树来进行维护。在知乎上看到一个回答,挺好的:

Vuex的主要作用是各组件间的状态同步(以及同一组件再次显示时的状态保持)。
特别是非数据库内容。比如网页右上角的搜索框,并不像日志列表那样对应数据库内容。
如果不希望每次进入有搜索框的模板页面,搜索框内容都被重置,那么就需要高于组件的架构


题外话:
以往的操作是:
- parentA
- childB
- childC
子组件(B,C)要调用A的回调,那么通过props传递到B,C即可。
A中要调用B.C的方法/属性,那么也可以通过props回调,然后把B,C的属性/方法作为参数 this.props.Afn(bVal,cVal,bFn,cFn)这样。(当然这是在B,C内部操作)。如果一定要在A中执行,可以this.ref.B.blah(以react为例)
在vue中,通信中props的部分跟react一样,当然也可以通过(特别是孙孙组件这种层级特别多的)事件,B,C中emit,A中on
而事件也适用于sibling之间的通信,如B,C。
栗子可以看react


以shopping-cart为例来分析vuex的goods
子组件为cart和products。购物车和商品列表。


需要用vuex/Immutable的原因

  1. vue踩下的坑: props传递引用对象(浅复制)

    比如这边的wigetList就是一个数组对象,是作为editModal这个子组件的props进行传递的,而子组件的一个data:list以wigetList为初始值,当点击multiSelect(即传进来的是protocol:[]数组,变动这个数组时)等变动list的时候,由于传递引用,会导致外层的wigetList变动,造成新一轮的props更新,所有list中非引用的对象都会被重新初始化掉,(注意是非引用对象,像input值传进来,内部变动是不会影响外部的)
    应该是传类似于这种:
  1. [{
  2. input: 'tet', //不会改变外部
  3. select: ['test1','test2']//会作用于外部
  4. }]

这样就违背了数据单向传递的目的,那么所有引用这个wigetList的值都会相应的被变化。
应该是props传递进来的时候用的浅复制,类似于Object.assign.

对每个key遍历赋值,然后基本类型都赋值,但是引用赋的还是对象。
一种解决方案是传递immutable数据(蠢蠢的方法是JSON序列化掉然后传进来...)。
还有一种是虽然传引用,但是赋值(data用props初始化的时候)用深拷贝(这边用的lodash的深拷贝)。

  1. import cloneDeep from 'lodash/cloneDeep'
  2. data() {
  3. return {
  4. showModal: this.show,
  5. wigets: cloneDeep(this.wigetList), //here
  6. form: {...wigetTest}
  7. };
  8. },
  9. watch:{
  10. show(val){
  11. this.showModal = val;
  12. },
  13. wigetList(val){
  14. this.wigets = cloneDeep(val); //here ~
  15. }

  1. 全局维护tab. 当click tab时,dispatch一个“changeTab”的action,根store响应,根commit一个CHANGE_TAB的mutation(tab = newTab),然后同名的module里面的mutation执行(比如reset等等)。之前的方法是这样处理的:在page1中监听tab变动,等根的tab state变动完后reset.
  1. //page1:
  2. watch: {
  3. '$route'(to,from) {
  4. //监听tab导致的路由变动
  5. if(to.query && to.query.tab){
  6. this.$store.dispatch('changeTab',to.query.tab).then(()=>{
  7. this.reset();
  8. })
  9. }
  10. }
  11. },
  12. //根store
  13. const actions = {
  14. changeTab({commit},tab){
  15. //返回一个promise
  16. return new Promise((resolve,reject)=>{
  17. commit(types.CHANGE_TAB,tab);
  18. resolve();
  19. })
  20. }
  21. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注