uni-app状态管理进阶:Vuex最佳实践与性能优化 0 次阅读

状态管理是uni-app应用开发中的重要环节,本文将深入介绍Vuex在uni-app中的应用,以及如何构建高效的数据流方案。

1. Vuex基础配置

1.1 目录结构

1
2
3
4
5
6
7
8
9
10
store
├── index.js # 入口文件
├── state.js # 根级别的state
├── mutations.js # 根级别的mutations
├── actions.js # 根级别的actions
├── getters.js # 根级别的getters
└── modules # 模块目录
├── user.js # 用户模块
├── cart.js # 购物车模块
└── order.js # 订单模块

1.2 基础配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
import actions from './actions'
import getters from './getters'
import user from './modules/user'
import cart from './modules/cart'
import order from './modules/order'

Vue.use(Vuex)

const store = new Vuex.Store({
state,
mutations,
actions,
getters,
modules: {
user,
cart,
order
},
strict: process.env.NODE_ENV !== 'production'
})

export default store

2. 模块化设计

2.1 用户模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// store/modules/user.js
import { login, getUserInfo, updateUserInfo } from '@/api/user'

const state = {
token: uni.getStorageSync('token') || '',
userInfo: null,
permissions: []
}

const mutations = {
SET_TOKEN(state, token) {
state.token = token
uni.setStorageSync('token', token)
},
SET_USER_INFO(state, info) {
state.userInfo = info
},
SET_PERMISSIONS(state, permissions) {
state.permissions = permissions
},
CLEAR_USER_DATA(state) {
state.token = ''
state.userInfo = null
state.permissions = []
uni.removeStorageSync('token')
}
}

const actions = {
// 登录
async login({ commit }, params) {
try {
const { token } = await login(params)
commit('SET_TOKEN', token)
return token
} catch (err) {
throw new Error('登录失败')
}
},

// 获取用户信息
async getUserInfo({ commit }) {
try {
const { userInfo, permissions } = await getUserInfo()
commit('SET_USER_INFO', userInfo)
commit('SET_PERMISSIONS', permissions)
return userInfo
} catch (err) {
throw new Error('获取用户信息失败')
}
},

// 更新用户信息
async updateUserInfo({ commit }, params) {
try {
const info = await updateUserInfo(params)
commit('SET_USER_INFO', info)
return info
} catch (err) {
throw new Error('更新用户信息失败')
}
},

// 退出登录
logout({ commit }) {
commit('CLEAR_USER_DATA')
}
}

const getters = {
isLogin: state => !!state.token,
userInfo: state => state.userInfo || {},
permissions: state => state.permissions
}

export default {
namespaced: true,
state,
mutations,
actions,
getters
}

2.2 购物车模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// store/modules/cart.js
import { getCartList, updateCart, removeFromCart } from '@/api/cart'

const state = {
cartList: [],
selectedIds: []
}

const mutations = {
SET_CART_LIST(state, list) {
state.cartList = list
},
UPDATE_CART_ITEM(state, { id, data }) {
const index = state.cartList.findIndex(item => item.id === id)
if (index > -1) {
state.cartList[index] = { ...state.cartList[index], ...data }
}
},
REMOVE_CART_ITEM(state, id) {
state.cartList = state.cartList.filter(item => item.id !== id)
},
SET_SELECTED_IDS(state, ids) {
state.selectedIds = ids
}
}

const actions = {
// 获取购物车列表
async getCartList({ commit }) {
try {
const list = await getCartList()
commit('SET_CART_LIST', list)
return list
} catch (err) {
throw new Error('获取购物车列表失败')
}
},

// 更新购物车商品
async updateCartItem({ commit }, { id, data }) {
try {
await updateCart(id, data)
commit('UPDATE_CART_ITEM', { id, data })
} catch (err) {
throw new Error('更新购物车商品失败')
}
},

// 删除购物车商品
async removeCartItem({ commit }, id) {
try {
await removeFromCart(id)
commit('REMOVE_CART_ITEM', id)
} catch (err) {
throw new Error('删除购物车商品失败')
}
}
}

const getters = {
cartCount: state => state.cartList.length,
selectedCount: state => state.selectedIds.length,
totalPrice: state => {
return state.cartList
.filter(item => state.selectedIds.includes(item.id))
.reduce((total, item) => total + item.price * item.quantity, 0)
}
}

export default {
namespaced: true,
state,
mutations,
actions,
getters
}

3. 数据持久化

3.1 插件封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// store/plugins/persist.js
const STORAGE_KEY = 'vuex_storage'

export default function createPersistPlugin(options = {}) {
const {
key = STORAGE_KEY,
paths = [],
storage = uni.getStorageSync
} = options

// 获取持久化数据
const getState = () => {
try {
const data = storage(key)
return data ? JSON.parse(data) : {}
} catch (err) {
console.error('获取持久化数据失败:', err)
return {}
}
}

// 设置持久化数据
const setState = (state, paths) => {
try {
const data = paths.length
? paths.reduce((obj, path) => {
obj[path] = state[path]
return obj
}, {})
: state
storage(key, JSON.stringify(data))
} catch (err) {
console.error('设置持久化数据失败:', err)
}
}

return store => {
// 初始化时获取持久化数据
const data = getState()
if (Object.keys(data).length > 0) {
store.replaceState({
...store.state,
...data
})
}

// 监听数据变化
store.subscribe((mutation, state) => {
setState(state, paths)
})
}
}

3.2 使用插件

1
2
3
4
5
6
7
8
9
10
11
12
// store/index.js
import createPersistPlugin from './plugins/persist'

const persistPlugin = createPersistPlugin({
paths: ['user.token', 'user.userInfo', 'cart.cartList'],
storage: uni.setStorageSync
})

const store = new Vuex.Store({
// ...其他配置
plugins: [persistPlugin]
})

4. 性能优化

4.1 避免频繁更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// store/modules/cart.js
import { debounce } from '@/utils/tools'

const actions = {
// 使用防抖优化更新
updateCartItem: debounce(async function({ commit }, { id, data }) {
try {
await updateCart(id, data)
commit('UPDATE_CART_ITEM', { id, data })
} catch (err) {
throw new Error('更新购物车商品失败')
}
}, 300)
}

4.2 批量更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// store/modules/cart.js
const actions = {
// 批量更新购物车
async batchUpdateCart({ commit }, items) {
try {
await Promise.all(items.map(item => updateCart(item.id, item.data)))
items.forEach(item => {
commit('UPDATE_CART_ITEM', item)
})
} catch (err) {
throw new Error('批量更新购物车失败')
}
}
}

5. 辅助函数使用

5.1 组件中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<template>
<view class="cart">
<view class="total">总价: ¥{{ totalPrice }}</view>
<view
v-for="item in cartList"
:key="item.id"
class="cart-item"
>
<text>{{ item.name }}</text>
<text>¥{{ item.price }}</text>
<button @click="updateQuantity(item.id, item.quantity + 1)">+</button>
<text>{{ item.quantity }}</text>
<button @click="updateQuantity(item.id, item.quantity - 1)">-</button>
<button @click="removeItem(item.id)">删除</button>
</view>
</view>
</template>

<script>
import { mapState, mapGetters, mapActions } from 'vuex'

export default {
computed: {
...mapState('cart', ['cartList']),
...mapGetters('cart', ['totalPrice'])
},
methods: {
...mapActions('cart', ['updateCartItem', 'removeCartItem']),
async updateQuantity(id, quantity) {
if (quantity < 1) return
try {
await this.updateCartItem({ id, data: { quantity } })
uni.showToast({ title: '更新成功' })
} catch (err) {
uni.showToast({ title: err.message, icon: 'none' })
}
},
async removeItem(id) {
try {
await this.removeCartItem(id)
uni.showToast({ title: '删除成功' })
} catch (err) {
uni.showToast({ title: err.message, icon: 'none' })
}
}
}
}
</script>

5.2 自定义辅助函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// store/helpers.js
export function mapCache(namespace, maps) {
const res = {}

normalizeMap(maps).forEach(({ key, val }) => {
res[key] = function mappedCache() {
const store = this.$store
const cache = store._cache || (store._cache = {})
const cacheKey = namespace + ':' + key

if (cache[cacheKey]) {
return cache[cacheKey]
}

const value = typeof val === 'function'
? val.call(this, store.state[namespace], store.getters)
: store.state[namespace][val]

cache[cacheKey] = value
return value
}
})

return res
}

function normalizeMap(map) {
return Array.isArray(map)
? map.map(key => ({ key, val: key }))
: Object.keys(map).map(key => ({ key, val: map[key] }))
}

6. 最佳实践建议

  1. 合理划分模块
  2. 实现数据持久化
  3. 注意性能优化
  4. 使用辅助函数
  5. 做好错误处理

7. 总结

  1. 掌握Vuex基础配置
  2. 实现模块化设计
  3. 处理数据持久化
  4. 优化更新性能
  5. 灵活使用辅助函数

如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力!

上一篇 uni-app网络请求与缓存策略:构建高效的数据层
下一篇 uni-app路由与页面跳转:最佳实践与踩坑指南
感谢您的支持!
微信赞赏码 微信赞赏
支付宝赞赏码 支付宝赞赏