怎样治理 vue 项目中的数据?

vuex

怎样治理 vue 项目的数据?这个题目好像早已经有答案了,不过就是运用 vuex ,全局 store,全部运用保护一个超大的 Object,界面的显现状况跟着超大 Object 的变化而变化。

看起来很简单,不就保护一个 Object 嘛,实际上,要想组织好数据这块代码,必需事前对项目的数据组织明白得异常透辟,然后像设想数据库表一样把各个 module 的模样设想出来。实际上,个人以为设想 vuex 的 module 比设想数据库表庞杂许多:

  • 1、像数据库一样设想各个营业实体的表面,这部分设想难度应当和数据库表设想差不多;

  • 2、保护一堆 ajax 要求状况;

  • 3、怎样文雅地复用 module。比方有一个 PersonListModule,在一个页面上有两处要用到 PersonListModule 中的列表数据:一个是要在表格控件内里展现,一个是要在下拉控件内里展现,每一个控件中展现的列表数据挑选前提不一样;

  • 4、怎样同步 vuex 中的数据和服务器端数据。vuex 的超大 Object 能够看作服务器端数据在客户端内存中的一个缓存,怎样设想这个缓存的同步战略?

关于3、4两个题目,连系起来更恐惧:同步服务器端数据到 PersonListModule 的同时,还要斟酌怎样从 PersonListModule 中挑选出分页数据到页面展现,还要挑选出多个列表,还要斟酌在什么机遇从新更新“缓存”,想一想就头大。

假定我们才很壮大,设想出了能圆满应对上述题目的 store 计划,另有一个大题目拦着我们呢:怎样保证这套设想的可扩展性?因为营业体系变幻莫测,不晓得什么时候产物司理又有新主意了,我们得设想能很好地应对变幻莫测的需求吗?

为何这么难?题目终究出如今那里?

vuex 的头脑形式主如果从数据动手,由数据推导出界面的模样,这就须要先设想好 store 组织了。要设想好 store 组织,目测必需具有以下特质的工程师才做好:

  • 1、对项目营业相识异常深切;

  • 2、具有超强的笼统头脑才;

  • 3、经验丰富,能只管想到设想出的 store 组织能敷衍哪些状况、不能敷衍哪些状况。

第2条的门坎实在是太高了,能做到的前端工程师预计没多少。

怎样办?

我们不应当从数据推导出界面,而应当从界面推导出数据,逐层笼统。

比方如今要仿一个新浪微博首页,页面上重要包括的数据有:分组信息、微博列表、个人信息、一些引荐信息等,那末就设想一个只针对该页面的 module ,大抵组织为:

const homePageModule = {
  state: {
    groupList: [{
        id: 1,
        name: '名流明星',
        unread: 1
      },
      {
        id: 2,
        name: '同事',
        unread: 0
      }
    ],
    groupListExtraInfo: {
      // 初始显现多少个小组
      initShowCount: 5,
      loading: true
    },
    weiboList: [{
      id: 1,
      content: '<p>震动部</p>',
      author: 'yibuyisheng',
      createTime: '20170719234422'
    }],
    weiboListPageInfo: {
      loadingStatus: 'QUIET', // 三种取值:QUIET -> 没有加载;UP -> 向上加载;DOWN -> 向下加载
      // weiboList 的最先时候,可用这个时候戳做下一次的向上加载
      startTime: '20170719234422',
      // weiboList 的完毕时候,可用这个时候戳做下一次的向下加载
      endTime: '20170719234422'
    },
    self: {
      id: 1,
      nickname: 'yibuyisheng',
      email: 'yibuyisheng@163.com',
      avatar: 'http://weibo.com/2674779523/profile?rightmod=1&wvr=6&mod=personinfo',
      followedCount: 405,
      followerCount: 235,
      weiboCount: 1321
    },
    recommendMovies: [
      ...
    ],
    recommendTopics: [
      ...
    ]
    ...
  },
  mutations: {
    updateWeiboList(state, list) {
      ...
    }
  },
  actions: {
    appendWeiboList() {
      ...
    },
    prependWeiboList() {
      ...
    }
  }
};

针对这个页面,这个组织,各个处置惩罚逻辑就详细化、特别化了,代码写起来异常轻松。

代码复用?

假定如今有个小组页面,点进去后能够看到该小组一切成员发的微博,因为是一个新的页面,所以须要新起一个 module ,这也意味着要重复写一遍 weiboList 相干的代码,岂不蛋疼!

此时能够斟酌写一个 createWeiboListModule() 函数,用于建立这类通用 module ,然后再写一个 mergeModules() 函数,把 createWeiboListModule() 函数建立出来的 module 对象和各页面特别的 module 兼并起来,模样看起来大抵是如许:

mergeModules(createWeiboListModule(), {
  state: {
    ...
  },
  mutations: {
    ...
  },
  actions: {
    ...
  }
});

碰到须要复用的才抽取通用逻辑,很天然,很简单。

怎样连系 vue 组件?

上面的组织有一个很大的题目,就是不能很好地和 vue 组件连系。比方,要让微博首页和分组页面中的微博列表能复用 weiboList 相干代码,那末 weiboList 涉及到的 state、action、mutation、getter 的定名都要只管保持一致,不然就要传一个 nameMap(定名映照)给两个页面通用的 WeiboListComponent 组件,看起来就像如许:

<weibo-list-component :name-map="{weiboList: 'homePageWeiboList'}"></weibo-list-component>

几乎蛋疼!

好吧,那就严厉束缚这两个页面的 state、action、mutation、getter 定名都保持一致吧!

几乎超等蛋疼!

此时能够斟酌用 namespace 来处理这个题目,比方上面的 homePageModule 能够把 weiboList 拆分出来:

const store = new vuex.Store({
  ...,

  modules: {
    'page:home': {
      state: {
        groupList: [{
            id: 1,
            name: '名流明星',
            unread: 1
          },
          {
            id: 2,
            name: '同事',
            unread: 0
          }
        ],
        groupListExtraInfo: {
          // 初始显现多少个小组
          initShowCount: 5,
          loading: true
        },
        self: {
          id: 1,
          nickname: 'yibuyisheng',
          email: 'yibuyisheng@163.com',
          avatar: 'http://weibo.com/2674779523/profile?rightmod=1&wvr=6&mod=personinfo',
          followedCount: 405,
          followerCount: 235,
          weiboCount: 1321
        },
        recommendMovies: [
          ...
        ],
        recommendTopics: [
            ...
          ]
          ...
      },
    },
    'page:home:weiboList': createWeiboListModule(...)
  }

  ...
});

如许一来,只要给 vue 组件传一个 namespace 参数就好了:

<weibo-list-component namespace="page:home:weiboList"></weibo-list-component>

嗯,看起来挺好的!

怎样处置惩罚“store 缓存”?

能够在上一个题目处理的基础上,加上缓存功用,目测有大把现成的缓存战略能够参考(服务器端都玩儿烂了),因为绝大部分体系并不须要这层缓存功用,所以此处不赘述。

就如许了吗?

上述计划,头脑方向的确是致使末了执行起来轻松了许多,从详细到笼统的历程,很天然,相符思索习气。然则终究的代码照样会很轻易搞得很乱的:

  • 1、mergeModules() 要照应种种兼并战略;

  • 2、createXXXModule() 方法会抽出许多层。比方能够从 createWeiboListModule() 抽出来 createContinuousListModule() ,用于组织通用的具有“向前向后”加载才的列表 Module,终究可能会构成一条经常的“继续链”,须要本身去定义保护这套继续逻辑,心累。

实在上面两条一看,就晓得有现成的处理计划了: class。

参考此处完成:https://github.com/yibuyishen…(代码还在完美中)。

详细营业代码写起来就像是如许了:

class ContinuousList extends BaseModule {
    state = {
        list: [],
        pageInfo: {
            loadingStatus: 'QUIET',
            startTime: '20170720003939',
            endTime: '20170720003939'
        }
    }
    
    @action
    async appendList(...) { 
        ...
        const result = await request('some url', params);
        this.updateList(result.list);
        ...
    }
    
    @action
    prependList(...) { ... }
}

class WeiboList extends ContinuousList {
    
    @action
    async voteUp(...) {
        ...
        await request('some url', params);
        const weiboDetail = await updateWeibo('some url', params.weiboId);
        const newList = this.state.list.map((wb) => {
            return wb.id === weiboDetail.id ? weiboDetail : wb;
        });
        this.updateList(newList);
        ...
    }
}

@composition(WeiboList)
class HomePage extends BaseModule {

    $namespace = 'page:home:';
    
    ...
    @action
    requestRecommendInfo(...) {
        ...
    }
    ...
}

HomePage.register();

在对应的 HomePage.vue 内里,大抵是如许:

<template>
    <div class="home-page-view">
        ...
        <weibo-list-component namespace="page:home:weiboList"></weibo-list-component>
        ...
    </div>
</template>
<script>
export default {
    created() {
        ...
        const constants = this.getConstants('page:home');
        this.$store.dispatch(constants.REQUEST_RECOMMEND_INFO, params);
        ...
    }
};
</script>

WeiboListComponent 组件大抵是如许:

<template>
    <div class="weibo-list-component">
        ...
    </div>
</template>
<script>
export default {
    props: {
        namespace: {
            type: String,
            required: true
        }
    },
    computed: {
        weiboList() {
            const constants = this.getConstants(this.namespace);
            return this.$store.getters[constants.LIST];
        }
    },
    created() {
        ...
        const constants = this.getConstants(this.namespace);
        this.$store.dispatch(constants.APPEND_LIST, params);
        ...
    }
};
</script>

总结

实在就是换一种思绪:从界面推导数据,从详细到笼统。

    原文作者:yibuyisheng
    原文地址: https://segmentfault.com/a/1190000010264128
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞