ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

状态管理 - 全局状态管理工具

2022-01-03 11:03:18  阅读:140  来源: 互联网

标签:状态 search index 数据 管理工具 state searchData 全局 vuex


文章目录

一、单向数据流
1. 理念示意图

“单向数据流” 理念示意图
在这里插入图片描述

2. 简述
  • state,驱动应用的数据源;
  • view,以声明方式将 state 映射到视图;
  • actions,响应在 view 上的用户输入导致的状态变化。

但是,当我们的应用遇到**多个组件共享状态(数据)**时,单向数据流的简洁性很容易被破坏(回忆 search-blogsearch-history 的代码):

  • 多个视图依赖于同一状态(数据)。
  • 来自不同视图的行为需要变更同一状态(数据)。

所以我们不得不通过 父子组件传递数据 的方式,来频繁的修改状态(数据)。但是这种方式是 非常脆弱,通常会导致无法维护的代码。

二、什么是全局状态管理模式

所以我们就需要就想到了一种方案,我们把:

把多个组件之间共用的数据抽离出来,通过一个 单例模式 进行管理,而这种管理的方式就叫做【全局状态管理模式】。

具备 【全局状态管理模式】 的库,就是 【全局状态管理工具】

而在 vue 中存在一个专门的 【全局状态管理工具】,叫做 vuex

因为 uniapp 追随 vue微信小程序 的语法,所以我们可以在 uniapp 中使用 vuex 来进行 【全局状态管理】,并且这是一个 非常被推荐 的选择。

三、重点概念
3.1. 什么是全局状态管理模式?

模式:把多个组件之间共用的数据抽离出来,通过一个 单例模式 进行管理。

3.2.全局状态管理工具?

工具:具备 【全局状态管理模式】 的库

3.3. 什么是 vuex

vue 应用程序进行全局状态管理的工具

四、在项目中导入 vuex
4.1. 状态管理配置

在项目根目录下创建store文件夹,并在store文件夹下创建index.js
内容如下:

// 1. 导入 Vue 和 Vuex
import Vue from 'vue';

// uniapp 已默认安装,不需要重新下载
import Vuex from 'vuex';

// 2. 安装 Vuex 插件
Vue.use(Vuex);

// 3. 创建 store 实例
const store = new Vuex.Store({});

export default store;
4.2. 注册vuex

在 main.js 中注册 vuex 插件

// 导入 vuex 实例
import store from './store';
...

const app = new Vue({
  ...App,
  store // 挂载实例对象
});
app.$mount();
五、测试 vuex 是否导入成功

,可以按照模块单独配置,然后,在index.js中引入,来进行对各模块的统一状态管理

5.1. 创建搜索模块

在store文件夹下,创建modules文件夹,并在此文件夹下创建search模块(search.js)
内容如下:

export default {
  // 独立命名空间
  namespaced: true,
  // 通过 state 声明数据
  state: () => {
    return {
      msg: 'hello vuex'
    };
  }
};
5.2. 注入模块

index.js 中注入模块

...
// 导入 search.js 暴露的对象
import search from './modules/search';

// 2. 安装 Vuex 插件
Vue.use(Vuex);
// 3. 创建 store 实例
const store = new Vuex.Store({
  modules: {
    search
  }
});
export default store;
5.3. 页面使用模块中的数据

有3步:

  1. 导入 mapState 函数
  2. 在 computed 中,通过 mapState 函数,注册 state 中的数据,导入之后的数据可直接使用(就像使用 data 中的数据一样)
    // mapState(模块名, [‘字段名’,‘字段名’,‘字段名’])
  3. 使用导入的 vuex 模块中的数据

index.vue 中使用 模块中的数据

<template>
  <view class="search-blog-container">
    <!-- 3. 使用导入的 vuex 模块中的数据 -->
    <view>{{ msg }}</view>
    ...
  </view>
</template>

<script>
// 1. 导入 mapState 函数
import { mapState } from 'vuex';
...
export default {
 ...
  computed: {
    // 2. 在 computed 中,通过 mapState 函数,注册 state 中的数据,导入之后的数据可直接使用(就像使用 data 中的数据一样)
    // mapState(模块名, ['字段名','字段名','字段名'])
    ...mapState('search', ['msg'])
  }
};
</script>
5.4. 构建 search 模块

search.js

export default {
  // 独立命名空间
  namespaced: true,
  // 通过 state 声明数据
  state: () => ({
    searchData: []
  }),
  // 更改 state 数据的唯一方式是:提交 mutations
  mutations: {
    /**
     * 添加数据
     */
    addSearchData(state, val) {
      if (!val) return;
      const index = state.searchData.findIndex((item) => item === val);
      if (index !== -1) {
        state.searchData.splice(index, 1);
      }
      state.searchData.unshift(val);
    },
    /**
     * 删除指定数据
     */
    removeSearchData(state, index) {
      state.searchData.splice(index, 1);
    },
    /**
     * 删除所有数据
     */
    removeAllSearchData(state) {
      state.searchData = [];
    }
  }
};

5.5. 对vuex数据操作

对vuex数据操作步骤:

  1. 导入mapMutations 函数,处理mutation的问题
  2. 利用 mapMutations函数,可以直接把vuex中的mutation合并到当前组件的methods中,合并之后,使用mutation就像使用methods中的方法一样
<template>
  <view class="hot-container">

    <view v-for="(item, index) in tabData" :key="index">
      {{ item.label }} - {{ index }}
    </view>
  </view>
</template>

<script>
// 1. 导入 mapState 函数
// 2. 导入mapMutations 函数,处理mutation的问题
import { mapState, mapMutations } from 'vuex';
import { getHotTabs } from 'api/hot';
export default {
  data() {
    return {
      tabData: [],
    };
  },
  // 组件实例配置完成,但是DOM尚未渲染,进行网络请求,配置响应数据
  created() {
    this.loadHotTabs();
  },
  methods: {
    // 利用 mapMutations函数,可以直接把vuex中的mutation合并到当前组件的methods中,合并之后,
    // 使用mutation就像使用methods中的方法一样
    ...mapMutations('search', ['removeSearchData', 'removeAllSearchData']),

    // 删除所有数据
    onDelAllClick() {
      this.removeAllSearchData();
    },
    //  删除指定数据 index角标
    onClearAll(item, index) {
      this.removeSearchData(index);
    },
    /**
     * 获取热搜标题数据
     */
    async loadHotTabs() {
      // uniapp 支持 async await
      const  res= await getHotTabs();
      this.tabData = res.content;
      console.log('res', res.content);
    },
  },
  computed: {
    // 2. 在 computed 中,通过 mapState 函数,注册 state 中的数据,导入之后的数据可直接使用(就像使用 data 中的数据一样)
    // mapState(模块名, ['字段名','字段名','字段名'])
    ...mapState('search', ['searchData']),
  },
};
</script>

<style lang="scss"></style>

六、vuex数据持久化

已完成 数据和组件的分离,所以【数据持久化】不需要涉及到组件内的代码
用到的api是uni.setStorage,参数key value形式
案例演示:搜索模块

6.1. 搜索模块数据持久化

store/search.js

const STORAGE_KEY = 'search-list';
const HISTORY_MAX = 10;

export default {
  // 独立命名空间
  namespaced: true,
  // 通过 state 声明数据
  state: () => ({
    // 优先从 storage 中读取
    searchData: uni.getStorageSync(STORAGE_KEY) || []
  }),
  // 更改 state 数据的唯一方式是:提交 mutations
  mutations: {
    /**
     * 保存数据到 storage
     */
    saveToStorage(state) {
      uni.setStorage({
        key: STORAGE_KEY,
        data: state.searchData
      });
    },
    /**
     * 添加数据
     */
    addSearchData(state, val) {
      if (!val) return;
      const index = state.searchData.findIndex((item) => item === val);
      if (index !== -1) {
        state.searchData.splice(index, 1);
      }
      // 判断是否超过了最大缓存数量
      if (state.searchData.length > HISTORY_MAX) {
        state.searchData.splice(HISTORY_MAX - 1, state.searchData.length - HISTORY_MAX - 1);
      }

      state.searchData.unshift(val);
      // 调用 saveToStorage
      this.commit('search/saveToStorage');
    },
    /**
     * 删除指定数据
     */
    removeSearchData(state, index) {
      state.searchData.splice(index, 1);
      // 调用 saveToStorage
      this.commit('search/saveToStorage');
    },
    /**
     * 删除所有数据
     */
    removeAllSearchData(state) {
      state.searchData = [];
      // 调用 saveToStorage
      this.commit('search/saveToStorage');
    }
  }
};

6.2. 搜索api

搜索结果 - 获取搜索结果数据

import request from '../utils/request';

/**
 * 搜索结果
 */
export function getSearchResult(data) {
  return request({
    url: '/search',
    data
  });
}
6.3. 页面使用

search-result-list.vue

<template>
  <view> 搜索结果 </view>
</template>

<script>
import { getSearchResult } from 'api/search';
export default {
  name: 'search-result-list',
  props: {
    // 搜索关键字
    queryStr: {
      type: String,
      required: true
    }
  },
  data() {
    return {
      // 数据源
      resultList: [],
      // 页数
      page: 1
    };
  },
  created() {
    this.loadSearchResult();
  },
  methods: {
    /**
     * 获取搜索数据
     */
    async loadSearchResult() {
      const { data: res } = await getSearchResult({
        q: this.queryStr,
        p: this.page
      });
      this.resultList = res.list;
      console.log(this.resultList);
    }
  }
};
</script>

<style lang="scss"></style>

标签:状态,search,index,数据,管理工具,state,searchData,全局,vuex
来源: https://blog.csdn.net/weixin_40816738/article/details/122284380

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有