Vuex使用指南:狀態管理

一、什么是狀態管理?為什么需要 Vuex?

1. 狀態管理的基本概念

在 Vue 應用中,狀態指的是應用中的數據。例如:

  • 用戶登錄狀態
  • 購物車中的商品
  • 文章列表的分頁信息

狀態管理就是對這些數據的創建、讀取、更新和刪除進行有效管理。

2. 為什么需要 Vuex?

在小型應用中,我們可以通過?props?和?events?實現組件間通信。但在中大型應用中,這種方式會面臨以下問題:

  • 多層級組件通信復雜:跨級組件通信需要通過中間組件層層傳遞
  • 狀態共享困難:多個不相關組件需要共享同一狀態時,代碼會變得混亂
  • 狀態變化不可追蹤:數據流向不清晰,調試困難

Vuex 通過集中式存儲應用的所有組件的狀態,并以相應的規則保證狀態以一種可預測的方式發生變化,解決了上述問題。

二、Vuex 核心概念

Vuex 的核心由以下幾個部分組成:

1.?State:應用狀態的單一數據源

State 是存儲應用狀態的對象,類似于組件中的?data。但與組件的?data?不同的是,Vuex 的 state 是全局共享的。

// store.js
const store = createStore({state: {count: 0,user: null,cartItems: []}
})

組件可以通過?this.$store.state?訪問這些狀態:

<template><div><p>Count: {{ $store.state.count }}</p></div>
</template>
2.?Getters:類似于計算屬性,獲取派生狀態

Getters 用于獲取 state 經過處理后的值,類似于組件中的計算屬性。

// store.js
const store = createStore({state: {todos: [{ id: 1, text: 'Learn Vuex', completed: true },{ id: 2, text: 'Build an app', completed: false }]},getters: {completedTodos(state) {return state.todos.filter(todo => todo.completed);}}
})

組件中使用:

<template><div><p>Completed todos: {{ $store.getters.completedTodos.length }}</p></div>
</template>
3.?Mutations:更改 state 的唯一方法

Mutations 是唯一可以修改 state 的地方,并且必須是同步的。

// store.js
const store = createStore({state: {count: 0},mutations: {increment(state) {state.count++;},incrementBy(state, payload) {state.count += payload;}}
})

組件中通過?commit?觸發 mutation:

<script>
export default {methods: {handleIncrement() {this.$store.commit('increment'); // 觸發 increment mutationthis.$store.commit('incrementBy', 5); // 傳遞參數}}
}
</script>
4.?Actions:處理異步操作

Actions 用于處理異步操作(如 API 請求),完成后通過?commit?提交 mutation。

// store.js
const store = createStore({state: {user: null,loading: false},mutations: {SET_USER(state, user) {state.user = user;},SET_LOADING(state, loading) {state.loading = loading;}},actions: {async fetchUser({ commit }) {commit('SET_LOADING', true);try {const response = await fetch('/api/user');const user = await response.json();commit('SET_USER', user);} catch (error) {console.error('Failed to fetch user', error);} finally {commit('SET_LOADING', false);}}}
})

組件中通過?dispatch?觸發 action:

<script>
export default {methods: {async loadUser() {await this.$store.dispatch('fetchUser');}}
}
</script>
5.?Modules:模塊化管理大型應用

當應用變得復雜時,可以將 store 分割成多個模塊,每個模塊有自己的 state、mutations、actions 和 getters。

// store/modules/cart.js
export default {namespaced: true, // 啟用命名空間state: {items: []},mutations: {ADD_ITEM(state, item) {state.items.push(item);}},actions: {addToCart({ commit }, item) {commit('ADD_ITEM', item);}},getters: {itemCount(state) {return state.items.length;}}
}

在根 store 中注冊模塊:

// store/index.js
import { createStore } from 'vuex'
import cart from './modules/cart'
import user from './modules/user'export default createStore({modules: {cart,user}
})

三、Vuex 工作流程:單向數據流

Vuex 采用單向數據流的設計理念,所有狀態變更都遵循固定的流程:

  1. 視圖觸發 Action:組件通過?dispatch?觸發 action
  2. Action 處理異步邏輯:如 API 請求、定時器等
  3. Action 提交 Mutation:完成后通過?commit?提交 mutation
  4. Mutation 修改 State:mutation 是唯一允許修改 state 的地方
  5. State 變化觸發視圖更新:Vue 的響應式系統會自動更新所有依賴該 state 的組件
組件(dispatch) → Action(commit) → Mutation(modify) → State → 組件更新

四、實戰案例:使用 Vuex 構建購物車應用

下面通過一個簡單的購物車應用來演示 Vuex 的實際應用。

實現效果:

vuex實現購物車

1. 項目結構
src/├── store/│    ├── index.js       # 根 store│    └── modules/│         └── cart.js   # 購物車模塊├── components/│    ├── ProductList.vue  # 商品列表│    ├── Cart.vue         # 購物車│    └── Navbar.vue       # 導航欄└── App.vue
2. 創建購物車模塊
// store/modules/cart.js
export default {// 設置命名空間,以便在多個模塊中避免狀態、getters、mutations和actions的命名沖突namespaced: true,// 定義模塊的狀態state: {// 購物車中的商品項items: []},// 定義獲取狀態的getter函數getters: {// 計算購物車中的商品數量itemCount: state => state.items.length,// 計算購物車中商品的總價totalPrice: state => {return state.items.reduce((total, item) => {return total + item.price * item.quantity;}, 0);}},// 定義直接修改狀態的mutation函數mutations: {// 添加商品到購物車ADD_ITEM(state, product) {// 查找購物車中是否已存在該商品const existingItem = state.items.find(item => item.id === product.id);if (existingItem) {// 如果存在,增加該商品的數量existingItem.quantity++;} else {// 如果不存在,將該商品添加到購物車中,并設置數量為1state.items.push({ ...product, quantity: 1 });}},// 從購物車中移除商品REMOVE_ITEM(state, productId) {// 過濾掉要移除的商品state.items = state.items.filter(item => item.id !== productId);},// 清空購物車CLEAR_CART(state) {// 將購物車中的商品項設置為空數組state.items = [];}},// 定義異步操作和提交mutation的action函數actions: {// 將商品添加到購物車的actionaddToCart({ commit }, product) {// 提交ADD_ITEM的mutationcommit('ADD_ITEM', product);},// 從購物車中移除商品的actionremoveFromCart({ commit }, productId) {// 提交REMOVE_ITEM的mutationcommit('REMOVE_ITEM', productId);},// 清空購物車的actionclearCart({ commit }) {// 提交CLEAR_CART的mutationcommit('CLEAR_CART');}}
};
3. 注冊模塊到根 store
// store/index.js
import { createStore } from 'vuex';
import cart from './modules/cart';export default createStore({modules: {cart}
});
4. 創建商品列表組件
<!-- components/ProductList.vue -->
<template><div class="product-list"><h2>商品列表</h2><div class="products"><div v-for="product in products" :key="product.id" class="product"><img :src="product.image" alt="Product" /><h3>{{ product.name }}</h3><p>{{ product.price }} 元</p><button @click="addToCart(product)">加入購物車</button></div></div></div>
</template><script>
export default {data() {return {products: [{ id: 1, name: 'iPhone 13', price: 6999, image: 'https://picsum.photos/200/300?random=1' },{ id: 2, name: 'MacBook Air', price: 9999, image: 'https://picsum.photos/200/300?random=2' },{ id: 3, name: 'iPad Pro', price: 7999, image: 'https://picsum.photos/200/300?random=3' }]};},methods: {addToCart(product) {this.$store.dispatch('cart/addToCart', product);alert(`${product.name} 已添加到購物車`);}}
};
</script>
5. 創建購物車組件
<!-- components/Cart.vue -->
<template><div class="cart"><h2>購物車</h2><div v-if="cartItems.length === 0" class="empty-cart">購物車為空</div><div v-else><ul><li v-for="item in cartItems" :key="item.id" class="cart-item"><img :src="item.image" alt="Product" /><div class="item-info"><h3>{{ item.name }}</h3><p>{{ item.price }} 元 x {{ item.quantity }}</p><button @click="removeFromCart(item.id)">移除</button></div></li></ul><div class="cart-summary"><p>總計: {{ totalPrice }} 元</p><button @click="clearCart">清空購物車</button></div></div></div>
</template><script>
export default {computed: {cartItems() {return this.$store.state.cart.items;},totalPrice() {return this.$store.getters['cart/totalPrice'];}},methods: {removeFromCart(productId) {this.$store.dispatch('cart/removeFromCart', productId);},clearCart() {this.$store.dispatch('cart/clearCart');}}
};
</script>
6. 創建導航欄組件(顯示購物車數量)
<!-- components/Navbar.vue -->
<template><nav class="navbar"><div class="container"><a href="#" class="brand">Vuex 購物車</a><div class="cart-icon"><i class="fas fa-shopping-cart"></i><span class="cart-count">{{ cartItemCount }}</span></div></div></nav>
</template><script>
export default {computed: {cartItemCount() {return this.$store.getters['cart/itemCount'];}}
};
</script>
7. 在 App.vue 中組合所有組件
<!-- App.vue -->
<template><div id="app"><Navbar /><div class="container"><ProductList /><Cart /></div></div>
</template><script>
import Navbar from './components/Navbar.vue';
import ProductList from './components/ProductList.vue';
import Cart from './components/Cart.vue';export default {components: {Navbar,ProductList,Cart}
};
</script><style>
/* 全局樣式 */
body {font-family: Arial, sans-serif;margin: 0;padding: 0;
}.container {max-width: 1200px;margin: 0 auto;padding: 20px;
}.navbar {background-color: #333;color: white;padding: 10px 0;
}.navbar .container {display: flex;justify-content: space-between;align-items: center;
}.brand {font-size: 24px;text-decoration: none;color: white;
}.cart-icon {position: relative;cursor: pointer;
}.cart-count {position: absolute;top: -10px;right: -10px;background-color: red;color: white;border-radius: 50%;width: 20px;height: 20px;display: flex;justify-content: center;align-items: center;font-size: 12px;
}.product-list {margin-bottom: 40px;
}.products {display: grid;grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));gap: 20px;
}.product {border: 1px solid #ddd;padding: 15px;border-radius: 5px;text-align: center;
}.product img {max-width: 100%;height: 200px;object-fit: cover;margin-bottom: 10px;
}.product button {background-color: #4CAF50;color: white;border: none;padding: 10px 15px;cursor: pointer;border-radius: 5px;
}.product button:hover {background-color: #45a049;
}.cart-item {display: flex;align-items: center;border-bottom: 1px solid #ddd;padding: 15px 0;
}.cart-item img {width: 80px;height: 80px;object-fit: cover;margin-right: 15px;
}.item-info {flex: 1;
}.item-info button {background-color: #f44336;color: white;border: none;padding: 5px 10px;cursor: pointer;border-radius: 3px;
}.item-info button:hover {background-color: #d32f2f;
}.cart-summary {margin-top: 20px;text-align: right;
}.cart-summary button {background-color: #333;color: white;border: none;padding: 10px 15px;cursor: pointer;border-radius: 5px;
}.cart-summary button:hover {background-color: #555;
}.empty-cart {padding: 20px;text-align: center;color: #666;
}
</style>

五、Vuex 高級技巧

1. 使用輔助函數簡化代碼

Vuex 提供了?mapStatemapGettersmapMutations?和?mapActions?輔助函數來簡化組件中的代碼。

<template><div><p>Count: {{ count }}</p><button @click="increment">+</button></div>
</template><script>
import { mapState, mapMutations } from 'vuex';export default {computed: {...mapState(['count'])},methods: {...mapMutations(['increment'])}
}
</script>
2. 嚴格模式

在開發環境中啟用嚴格模式,確保所有狀態變更都通過 mutations。

// store/index.js
export default createStore({strict: process.env.NODE_ENV !== 'production'
});
3. 插件機制

Vuex 插件是一個函數,接收 store 作為唯一參數,可以用于記錄日志、持久化存儲等。

// store/plugins/logger.js
export default function logger(store) {store.subscribe((mutation, state) => {console.log('Mutation:', mutation.type);console.log('Payload:', mutation.payload);console.log('State after mutation:', state);});
}// store/index.js
import logger from './plugins/logger';export default createStore({plugins: [logger]
});
4. 狀態持久化

使用?vuex-persistedstate?插件將 state 持久化到本地存儲。

npm install vuex-persistedstate
// store/index.js
import createPersistedState from 'vuex-persistedstate';export default createStore({plugins: [createPersistedState()]
});

六、Vuex 常見問題與解決方案

1. 何時使用 Vuex?
  • 多組件共享狀態
  • 組件間通信復雜
  • 狀態需要被多個視圖監聽
  • 中大型應用
2. 與 Vue Router 結合使用

在路由導航守衛中訪問 Vuex 狀態:

router.beforeEach((to, from, next) => {if (to.meta.requiresAuth && !store.state.user) {next('/login');} else {next();}
});

3. 性能優化
  • 避免在大型列表中頻繁修改 state
  • 使用?mapState?和?mapGetters?緩存計算結果
  • 對大型數據使用?Vue.set()?或?store.replaceState()

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/81840.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/81840.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/81840.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【信息系統項目管理師-論文真題】2007下半年論文詳解(包括解題思路和寫作要點)

更多內容請見: 備考信息系統項目管理師-專欄介紹和目錄 文章目錄 試題1:大型項目的計劃與監控1、寫作要點2、解題思路大型信息系統項目的組織制訂大型信息系統項目進度計劃的方法試題2:組織級項目管理的績效考核1、寫作要點2、解題思路在項目考核過程中會遇到哪些問題項目的…

項目管理學習-CSPM(1)

01引言 最近在學習CSPM的課程&#xff0c;有部分的內容自己還是受益匪淺的&#xff0c;建議有需要提升項目管理能力的同學可以以考促學的方式進行學習&#xff0c;下面整理了一部分內容和大家分享和學習。CSPM全稱 China Standards Project Management&#xff0c;中文名項目管…

介紹分治、動態規劃、回溯分別是什么?有什么聯系和區別?給出對象的場景和java代碼?

一、分治算法&#xff08;Divide and Conquer&#xff09; 概念&#xff1a; 分治算法是將一個復雜問題分成若干個子問題&#xff0c;每個子問題結構與原問題類似&#xff0c;然后遞歸地解決這些子問題&#xff0c;最后將子問題的結果合并得到原問題的解。 特點&#xff1a;…

解鎖DeepSeek模型微調:從小白到高手的進階之路

目錄 一、DeepSeek 模型初相識二、探秘微調原理2.1 遷移學習基礎2.2 微調的參數更新機制 三、數據準備3.1 數據收集3.2 數據標注3.3 數據預處理 四、模型選擇與加載4.1 選擇合適的預訓練模型4.2 加載模型 五、微調訓練實戰5.1 確定微調策略5.2 設置訓練參數5.3 訓練過程 六、模…

端到端觀測分析:從前端負載均衡到后端服務

前言 我們在做系統運維保障的時候&#xff0c;關注從前端負載均衡到后端服務的流量情況是很有必要的&#xff0c;可以了解每個后端服務實例接收的流量大小&#xff0c;這有助于確定資源分配是否合理&#xff0c;能夠幫助找出后端服務中的性能瓶頸。同時&#xff0c;當系統出現…

Ubuntu下OCC7.9+Qt5 快速搭建3D可視化框架

Ubuntu下OCC7.9+Qt5搭建簡易的項目框架 近兩年國產CAD替代如日中天,而幾何內核作為CAD軟件的核心組件之一,當前有且僅有唯一開源的幾何內核庫即OCCT;這里為各位自立于投入CAD開發或正在學習OCC庫的小伙伴們奉獻上一個快速搭建QT+OCC的項目框架; 本文介紹了Qt5+Occ 顯示幾何…

C++類與對象—下:夯實面向對象編程的階梯

9. 賦值運算符重載 9.1 運算符重載 在 C 里&#xff0c;運算符重載能夠讓自定義類型的對象像內置類型那樣使用運算符&#xff0c;這極大地提升了代碼的可讀性與可維護性。運算符重載本質上是一種特殊的函數&#xff0c;其函數名是 operator 加上要重載的運算符。 下面是運算…

【深度學習-Day 6】掌握 NumPy:ndarray 創建、索引、運算與性能優化指南

Langchain系列文章目錄 01-玩轉LangChain&#xff1a;從模型調用到Prompt模板與輸出解析的完整指南 02-玩轉 LangChain Memory 模塊&#xff1a;四種記憶類型詳解及應用場景全覆蓋 03-全面掌握 LangChain&#xff1a;從核心鏈條構建到動態任務分配的實戰指南 04-玩轉 LangChai…

工程師 - 汽車分類

歐洲和中國按字母對汽車分類&#xff1a; **軸距**&#xff1a;簡單來說&#xff0c;就是前輪中心點到后輪中心點之間的距離&#xff0c;也就是前輪軸和后輪軸之間的長度。根據軸距的大小&#xff0c;國際上通常把轎車分為以下幾類&#xff08;德國大眾汽車習慣用A\B\C\D分類&a…

[低代碼 + AI] 明道云與 Dify 的三種融合實踐方式詳解

隨著低代碼平臺和大語言模型工具的不斷發展,將企業數據與智能交互能力融合,成為提高辦公效率與自動化水平的關鍵一步。明道云作為一款成熟的低代碼平臺,Dify 則是一個支持自定義工作流的開源 LLM 應用框架。兩者結合,可以實現靈活、高效的智能化業務處理。 本文將詳解明道…

鼠標懸浮特效:常見6種背景類懸浮特效

鼠標懸浮特效&#xff1a;常見6種背景類懸浮特效 前言背景閃現效果預覽代碼展示 元素陰影效果預覽代碼展示 元素懸浮陰影效果預覽代碼展示 元素上浮陰影效果預覽代碼展示 元素邊框陰影效果預覽代碼展示 元素卷角效果預覽代碼展示 結語 前言 在之前的文章中&#xff0c;我們介紹…

[人機交互]理解與概念化交互

零.本章重點&#xff08;理解和分析用戶問題&#xff09; – 解釋“問題空間”的概念和含義 – 解釋如何概念化交互 – 描述什么是概念模型 – 討論將界面隱喻作為概念模型的利弊 – 討論界面具體化和抽象化各自的優缺點 – 概述概念設計和實際設計的關系 一.理解問題空間 簡單…

9.城市基礎設施更新工程

9.1 道路改造施工 9.1.1 道路改造施工內容 瀝青、水泥混凝土、砌塊路面、人行步道、綠化照明、附屬設施、交通標志、瀝青路面材料的再生利用 9.1.2 道路改造施工技術 1.瀝青路面病害及微表處理 1.病害處理 裂縫處理 10mm以內專業灌縫材料或熱瀝青灌縫、潮濕時乳化瀝青灌封…

Milvus(11):動態字段、可歸零和默認值

1 動態字段 Collections 的 Schema 中定義的所有字段都必須包含在要插入的實體中。如果希望某些字段是可選的&#xff0c;可以考慮啟用動態字段。 1.1 概述 在 Milvus 中&#xff0c;可以通過設置 Collections 中每個字段的名稱和數據類型來創建 Collections Schema。向 Schem…

LeetCode41?缺失的第一個正數

關聯LeetCode題號41 本題特點 數組&#xff0c;哈希表 本題思路 找缺失的最小正數&#xff0c;看舉例說明缺失的正數&#xff0c;一種情況是連續的最小的正數&#xff0c;一種是缺失連續但不是最小的正數驗證數組內數組是否連續&#xff0c;可以通過 nums[i]1 是否存nums組…

補題( Convolution, 二維卷積求輸出矩陣元素和最大值)

來源&#xff1a;https://codeforces.com/gym/105231/problem/H 題目描述&#xff1a; 一、題目分析 本題涉及深度學習中的二維卷積操作。給定一個nm的二維輸入矩陣I和一個kl的核矩陣K &#xff0c;通過特定公式計算得到(n - k 1)(m - l 1)的輸出矩陣O &#xff0c;要求在…

【Java ee初階】多線程(7)

一、線程池 線程池的一些參數&#xff1a; corePoolSize&#xff1a;核心線程數量 maximumPoolSize:核心線程數量臨時線程數量 上述是“java 的線程池策略”&#xff08;其他語言&#xff0c;其他庫的線程池可能不同&#xff09; keepAliveTime :臨時線程的存活時間.臨時線程…

Linux 常用指令詳解

Linux 操作系統中有大量強大的命令行工具&#xff0c;下面我將分類介紹一些最常用的指令及其用法。 ## 文件與目錄操作 ### 1. ls - 列出目錄內容 ls [選項] [目錄名] 常用選項&#xff1a; - -l&#xff1a;長格式顯示&#xff08;詳細信息&#xff09; - -a&#xff1a;顯…

uv安裝及使用

windows安裝參考&#xff1a; 什么是python uv&#xff0c;如何在windows上安裝uv&#xff0c;基礎的用法有哪些&#xff1f;_windows安裝uv-CSDN博客 https://zhuanlan.zhihu.com/p/6776864377 使用方式 方式1&#xff1a; 創建uv虛擬環境->激活環境->安裝依賴&…

C#實現Socket通信:基于TCP/IP協議的網絡編程

TCP/IP網絡模型 最上層的是應用層&#xff0c;也就是我們日常可以接觸到的&#xff0c;它會給數據添加對應的頭部&#xff0c;并傳輸給傳輸層&#xff0c;應用層是我們日常會接觸到的&#xff0c;比如HTTP&#xff0c;FTP&#xff0c;Telnet&#xff0c;DNS&#xff0c;SMTP。…