惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Attack and Defense Labs
Attack and Defense Labs
Engineering at Meta
Engineering at Meta
腾讯CDC
J
Java Code Geeks
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
G
Google Developers Blog
博客园 - 三生石上(FineUI控件)
Microsoft Azure Blog
Microsoft Azure Blog
The Cloudflare Blog
aimingoo的专栏
aimingoo的专栏
T
The Blog of Author Tim Ferriss
D
Darknet – Hacking Tools, Hacker News & Cyber Security
WordPress大学
WordPress大学
博客园_首页
I
InfoQ
NISL@THU
NISL@THU
Recorded Future
Recorded Future
Security Latest
Security Latest
K
Kaspersky official blog
L
Lohrmann on Cybersecurity
T
The Exploit Database - CXSecurity.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
U
Unit 42
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
www.infosecurity-magazine.com
www.infosecurity-magazine.com
C
CERT Recently Published Vulnerability Notes
W
WeLiveSecurity
Webroot Blog
Webroot Blog
Last Week in AI
Last Week in AI
AWS News Blog
AWS News Blog
IT之家
IT之家
S
Schneier on Security
雷峰网
雷峰网
Know Your Adversary
Know Your Adversary
T
Threat Research - Cisco Blogs
C
CXSECURITY Database RSS Feed - CXSecurity.com
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
L
LangChain Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
月光博客
月光博客
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Stack Overflow Blog
Stack Overflow Blog
有赞技术团队
有赞技术团队
云风的 BLOG
云风的 BLOG
G
GRAHAM CLULEY
O
OpenAI News
The Last Watchdog
The Last Watchdog
TaoSecurity Blog
TaoSecurity Blog
The GitHub Blog
The GitHub Blog
V
Vulnerabilities – Threatpost

吖远zzyの博客

记录一下豆包视频去水印的研究过程,以及fallback_api加密数据qAAB开头数据的解密。 | 吖远zzyの博客 解决华为开发者工具 DevEco Studio 登录跳转 localhost:10101 端口被阻止问题 | 吖远zzyの博客 微信小程序个人资质审核血泪史:踩坑,从反复被拒到神奇过审 | 吖远zzyの博客 如何实现公众号自动回复或做一个短视频无水印解析机器人? | 吖远zzyの博客 以后在手机上用 Termux 和 GitHub Actions 更新 Hexo 博客 | 吖远zzyの博客 必备!这款万能小程序能给抖音/豆包视频图集去除水印、还有有趣的测反应、玩成语模拟工具。 自制的一些免费API接口第二弹(获取QQ昵称、头像、抖音/豆包视频去水印等...) 告别原生导航栏:微信小程序自定义导航栏完美适配方案 在安卓手机上运行OpenClaw?当然可以,用Termux折腾OpenClaw安装QQ机器人的踩坑记录... | 吖远zzyの博客 个人开发工具之抖音直播录制工具:一款功能强大的Android直播录制应用 UniApp中Canvas绘图的易错点与踩坑指南 QQ频道机器人与UniApp开发:常见踩坑点与解决方案 UniApp中Canvas绘图不显示的常见问题与解决方案 Hexo博客实现随机文章功能的完整教程 QQ频道机器人Android客户端使用指南 | 吖远zzyの博客 安卓版QQ频道机器人APP客户端插件开发指南 | 吖远zzyの博客 2024年AI编程助手深度评测:哪款最适合你? uni-app地图定位踩坑记:地图功能和定位的那些坑 uni-app文件上传踩坑记:图片处理和上传全攻略 uni-app表单验证踩坑记:这些坑我替你踩过了 uni-app开发踩坑记录:新手必看的常见问题与解决方案 uni-app安全防护指南:构建可靠的跨端应用 uni-app性能优化指南:从加载到渲染的全方位提升 uni-app动画效果实战:从基础到高级的动画实现指南 uni-app组件开发实战:从基础到进阶的最佳实践 uni-app网络请求与缓存策略:构建高效的数据层 uni-app路由与页面跳转:最佳实践与踩坑指南
uni-app状态管理进阶:Vuex最佳实践与性能优化
吖远zzy · 2024-03-20 · via 吖远zzyの博客
  1. 1. 1. Vuex基础配置
    1. 1.1. 1.1 目录结构
    2. 1.2. 1.2 基础配置
  2. 2. 2. 模块化设计
    1. 2.1. 2.1 用户模块
    2. 2.2. 2.2 购物车模块
  3. 3. 3. 数据持久化
    1. 3.1. 3.1 插件封装
    2. 3.2. 3.2 使用插件
  4. 4. 4. 性能优化
    1. 4.1. 4.1 避免频繁更新
    2. 4.2. 4.2 批量更新
  5. 5. 5. 辅助函数使用
    1. 5.1. 5.1 组件中使用
    2. 5.2. 5.2 自定义辅助函数
  6. 6. 6. 最佳实践建议
  7. 7. 7. 总结

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. 灵活使用辅助函数

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