vue2狀態(tài)管理Vuex
Vuex 是一個(gè)專(zhuān)為 Vue.js應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理模式。它使用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),以及規(guī)則保證狀態(tài)只能按照規(guī)定的方式進(jìn)行修改。
-
State(狀態(tài))
:Vuex 使用單一狀態(tài)樹(shù),即一個(gè)對(duì)象包含全部的應(yīng)用層級(jí)狀態(tài)。這個(gè)狀態(tài)樹(shù)對(duì)應(yīng)著一個(gè)應(yīng)用中的所有狀態(tài)。 -
Getters(獲取器)
:Getters 允許你在模板中計(jì)算狀態(tài)。相當(dāng)于組件中的計(jì)算屬性??梢詫?duì) state 中的數(shù)據(jù)進(jìn)行處理和過(guò)濾。 -
Mutations(變更)
:Mutations 是 Vuex 修改狀態(tài)的唯一方式,它們是同步事務(wù)。每個(gè) mutation 都有一個(gè)字符串類(lèi)型的事件類(lèi)型 (type) 和 一個(gè)回調(diào)函數(shù),該回調(diào)函數(shù)接受 state 作為其第一個(gè)參數(shù)。 -
Actions(動(dòng)作)
:Actions 類(lèi)似于 Mutations,不同之處在于它們是異步的。Actions 提交 Mutations 來(lái)修改狀態(tài)。Actions 可以包含任意異步操作。 -
modules(模塊)
:Vuex 允許將 store 分割成模塊,每個(gè)模塊都有自己的 state、mutations、actions、getters。
輔助函數(shù):便于在組件中使用 Vuex 的功能
mapState
: 將 store 中的 state 映射為組件的計(jì)算屬性。mapGetters
: 將 store 中的 getters 映射為組件的計(jì)算屬性。mapMutations
: 將 store 中的 mutations 映射為組件的方法。mapActions
: 將 store 中的 actions 映射為組件的方法。
1、創(chuàng)建vue2項(xiàng)目
安裝腳手架:
npm install -g @vue/cli
創(chuàng)建vue2項(xiàng)目:vue create vue2_myapp
(輸入完命令后選擇vue2)
2、安裝Vuex依賴(lài)
在項(xiàng)目中使用npm或者yarn安裝Vuex。
npm install vuex
或yarn add vuex
或npm install vuex@^3.5.0 --save
(指定版本使用)
3、在src目錄下創(chuàng)建store目錄,在下面創(chuàng)建js用于存儲(chǔ)Vuex(命名通常為index.js或者store.js)
// store.js
import Vue from 'vue';
import Vuex from 'vuex';
import modulesA from './modules/modulesA'
Vue.use(Vuex);
export default new Vuex.Store({
state: {
//存儲(chǔ)公共數(shù)據(jù)
count: 100,
},
mutations: {
// 定義修改state數(shù)據(jù)的方法
increment(state) {
state.count++;
},
decrement(state) {
state.count--;
},
},
actions: {
// 使用異步的方式來(lái)觸發(fā)mutations中的方法進(jìn)行提交
},
getters: {
// 獲取狀態(tài)的方法
getCount: (state) => state.count,
},
modules: {
// 注冊(cè)拆分的模塊
a:{
//namespaced: true,//可以直接在modulesA配置在中
...modulesA
}
}
});
當(dāng)項(xiàng)目比較復(fù)雜時(shí),可以在src/store下增加module,將數(shù)據(jù)拆成模塊,下面舉一個(gè)moduleA示例
// moduleA.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
//注意此處是導(dǎo)出一個(gè)模塊不是new一個(gè)新vuex
export default{
namespaced: true,
state: {
//存儲(chǔ)公共數(shù)據(jù)
countA: 200,
},
mutations: {
// 定義修改state數(shù)據(jù)的方法
incrementA(state) {
state.countA++;
},
decrementA(state) {
state.countA--;
},
},
actions: {
// 使用異步的方式來(lái)觸發(fā)mutations中的方法進(jìn)行提交
incrementAsyncA({ commit }) {
// 模擬一個(gè)異步操作,例如從 API 獲取數(shù)據(jù)
setTimeout(() => {
commit('incrementA');
}, 1000);
},
},
getters: {
// 獲取狀態(tài)的方法
getCountA: (state) => state.countA,
},
};
4、在main.js中引入store
import Vue from 'vue'
import App from './App.vue'
import store from './store/store';//引入store
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store,//注冊(cè)store
}).$mount('#app')
5、在組件中使用
<template>
<div>
<h2>Root Module</h2>
<p>
Count from Root Module:
<!-- 顯示方式一:通過(guò)計(jì)算屬性獲取getter -->
{{ rootCount }} ||
<!-- 顯示方式二:直接獲取state中的值 -->
{{ $store.state.count }} ||
<!-- 顯示方式三:通過(guò)...mapState(['count'])直接使用count -->
{{ count }}
</p>
<button @click="incrementRoot">增加模塊 A 計(jì)數(shù)</button>
<button @click="decrementRoot">減少模塊 A 計(jì)數(shù)</button>
<h2>Module A</h2>
<p>
Count from Module A:
<!-- 顯示方式一:通過(guò)計(jì)算屬性獲取getter,需要配置namespaced -->
{{ moduleACount }} ||
<!-- 顯示方式二:通過(guò)在store中注冊(cè)的模塊直接使用modulesA的值 -->
{{ $store.state.a.countA }}
</p>
<button @click="incrementModuleA">增加模塊 A 計(jì)數(shù)</button>
<button @click="decrementModuleA">減少模塊 A 計(jì)數(shù)</button>
<button @click="incrementModuleAAsync">異步增加模塊 A 計(jì)數(shù)</button>
</div>
</template>
<script>
import { mapState,mapMutations,mapActions } from 'vuex';
export default {
computed: {
// 1、使用mapState方式獲取數(shù)據(jù)
// mapState使用方式一
...mapState(['count']),
// mapState使用方式二
...mapState({
rootCountMapState: 'count', // 將根模塊的 'getCount' 映射為 'rootCount'
moduleACount: 'a/getCountA', // 將模塊 'a' 的 'getCountA' 映射為 'moduleACount'
}),
// 2、使用 mapGetters 輔助函數(shù)將模塊中的 getters 映射到組件的計(jì)算屬性
rootCount() {
return this.$store.getters.getCount;
},
moduleACount() {
return this.$store.getters['a/getCountA'];
},
},
methods: {
// 1、使用mapMutations獲取mutations模塊方式一
...mapMutations({
incrementRoot: 'increment', // 將根模塊的 'increment' 映射為 'incrementRoot'
decrementRoot: 'decrement', // 將根模塊的 'decrement' 映射為 'decrementRoot'
incrementModuleA: 'a/incrementA', // 將模塊 'a' 的 'incrementA' 映射為 'incrementModuleA'
decrementModuleA: 'a/decrementA', // 將模塊 'a' 的 'decrementA' 映射為 'decrementModuleA'
}),
...mapActions({
incrementModuleAAsync: 'a/incrementAsyncA', // 將 'a/incrementAsyncA' 映射為 'incrementModuleAAsync'
}),
// 使用 mapMutations 輔助函數(shù)將模塊中的 mutations 映射到組件的方法二
incrementRoot() {
this.$store.commit('increment');
},
decrementRoot() {
this.$store.commit('decrement');
},
incrementModuleA() {
this.$store.commit('a/incrementA');
},
decrementModuleA() {
this.$store.commit('a/decrementA');
},
},
};
</script>
示例效果圖:
vue3狀態(tài)管理Pinia
-
State(狀態(tài))
: 在 Store 中定義的數(shù)據(jù),即應(yīng)用程序的狀態(tài)。狀態(tài)可以是基本類(lèi)型、對(duì)象、數(shù)組等。 -
Actions(操作)
: 在 Store 中定義的用于操作狀態(tài)的函數(shù)。Actions 可以是同步或異步的,通過(guò) this,你可以直接修改狀態(tài)。如果 actions 返回一個(gè) Promise,Pinia 將等待 Promise 完成,然后再繼續(xù)執(zhí)行其他代碼。 -
Getter(獲取器)
:獲取器允許你從狀態(tài)中派生出一些衍生數(shù)據(jù),類(lèi)似于計(jì)算屬性。通過(guò) getters,你可以在不直接修改狀態(tài)的情況下獲取和處理狀態(tài)的數(shù)據(jù)。
1、創(chuàng)建項(xiàng)目(參見(jiàn)上面vue2,輸入命令后選擇vue3即可)
2、安裝pinia
npm install pinia
或yarn add pinia
3、在main.js中引入
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia';
const app = createApp(App);
app.use(createPinia());
app.mount('#app')
4、在src下創(chuàng)建store/index.js
import { defineStore } from 'pinia';
export const useExampleStore = defineStore('example', {
state: () => ({
counter: 100,
}),
actions: {
increment() {
this.counter++;
console.log(this.counter);
},
decrement() {
this.counter--;
},
},
});
5、在組件中通過(guò)setup()使用,下面列舉了五種改變state數(shù)據(jù)的方式。
<!-- src/components/ExampleComponent.vue -->
<template>
<div>
<p>Counter: {{ exampleStore.counter }}</p>
<button @click="increment">Increment</button>
<button @click="decrement">Decrement</button>
</div>
</template>
<script setup>
import { useExampleStore } from '../store/index';
// 組合式
const exampleStore = useExampleStore();
const increment=()=>{
// 方式一:在store的action中操作
exampleStore.increment();
// 方式二:直接在應(yīng)用的組件中改變
// exampleStore.counter++;
// 方式三:使用$patch整體覆蓋
// exampleStore.$patch({
// counter:105
// })
// 方式四:使用$patch改變
// exampleStore.$patch((state)=>{
// if(state.counter){
// state.counter++;
// }
// })
// 方式五:使用$state覆蓋
// exampleStore.$state ={
// counter:122
// }
}
const decrement=()=>{
// exampleStore.decrement();
exampleStore.counter--;
}
// 選項(xiàng)式
// export default {
// setup() {
// const exampleStore = useExampleStore();
// return {
// exampleStore,
// increment: exampleStore.increment,
// decrement: exampleStore.decrement,
// };
// }
// };
</script>
示例效果圖:
Pinia與VueX區(qū)別:
- Vuex 為vue2打造的,Pinia為vue3打造的
- Pinia沒(méi)有mutations,直接通過(guò)actions進(jìn)行同步和異步操作,異步需要返回一個(gè)promise
- Pinia 沒(méi)有modules,設(shè)計(jì)更為分散,每個(gè)組件可以擁有自己的 Store。
- Vuex 組件通過(guò) mapState、mapMutations、mapActions 等輔助函數(shù)來(lái)訪(fǎng)問(wèn)存儲(chǔ)庫(kù)中的數(shù)據(jù)和操作。pinia通過(guò)setup 函數(shù)來(lái)引入和使用 Store,并通過(guò) Store 的實(shí)例訪(fǎng)問(wèn)狀態(tài)和操作。
- Vuex 對(duì) TypeScript 有良好的支持,但類(lèi)型推斷可能有時(shí)候會(huì)感覺(jué)有點(diǎn)繁瑣。Pinia 是使用 TypeScript 編寫(xiě)的,提供了更好的 TypeScript 支持,可以更輕松地推斷和利用類(lèi)型信息。
- vuex做數(shù)據(jù)持久化使用插件
vuex-persistedstate
,Pinia做數(shù)據(jù)持久化使用pinia-plugin-persist
react狀態(tài)管理Redux
Provider
:把父組件傳遞進(jìn)來(lái)的store對(duì)象放入react 上下文中,這樣connect組件就可以從上下文中獲取到store對(duì)象combineReducer
:store.state進(jìn)行分片管理,每個(gè)reducer管理state中的一部分。由于createStore只接受一個(gè)reducer,所以采用該方法生成一個(gè)最終的reducer中間件(Middleware)
:中間件是一個(gè)位于動(dòng)作派發(fā)和 Reducer 之間的攔截層。它允許你在動(dòng)作被派發(fā)到 Reducer 之前執(zhí)行額外的邏輯。State
:整個(gè) Redux 應(yīng)用程序的狀態(tài),它是只讀的。狀態(tài)的更新是通過(guò)觸發(fā)動(dòng)作來(lái)創(chuàng)建新的狀態(tài),而不是直接修改原有狀態(tài)。action
:更新state的狀態(tài)時(shí)用。dispatch
:觸發(fā)store修改state的命令,是createStore返回對(duì)象的一個(gè)方法connect
:從react上下文中取出store對(duì)象,訂閱store.state的變化,當(dāng)store state變化時(shí)調(diào)用自身的方法重新生成connect組件的state,被包裝組件便會(huì)被重新渲染。不會(huì)感知到store的存在,dispatch在這里也是非必須的。
connect的4個(gè)內(nèi)置組件: 狀態(tài)mapStateToProps
、動(dòng)作mapDispatchToProps
、屬性合并mergeProps
和 配置項(xiàng)options
異步中間件
:redux沒(méi)有直接提供執(zhí)行異步操作的方法,需要手動(dòng)集成中間件,最常用異步實(shí)現(xiàn)的中間件有redux-thunk
、redux-saga
1、搭建react+ts項(xiàng)目
npm install -g create-react-app
npx create-react-app my-react-ts-app --template typescript
2、安裝redux
npm install redux react-redux
3、在src下創(chuàng)建如下結(jié)構(gòu)
src/
– – store/
– – – – index.ts
– – – – reducers/
– – – – – – index.ts
– – – – – – counterReducer.ts
// src/store/index.ts
import { configureStore } from '@reduxjs/toolkit';
import rootReducer from './reducers';
const store = configureStore({
reducer: rootReducer
});
export default store;
// src/store/reducers/index.ts
// combineReducers 用于將多個(gè) reducer 組合成一個(gè)根 reducer
import { combineReducers } from 'redux';
import counterReducer from './counterReducer';
const rootReducer = combineReducers({
counter: counterReducer,
// 添加其他 reducer...
});
export default rootReducer;
// src/store/reducers/counterReducer.ts
// 從Redux中導(dǎo)入Action類(lèi)型,用于定義動(dòng)作對(duì)象
import { Action } from 'redux';
// 定義動(dòng)作類(lèi)型的常量,以避免拼寫(xiě)錯(cuò)誤
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
// Action Creators: 返回動(dòng)作對(duì)象的函數(shù)
export const increment = (): Action => ({ type: INCREMENT });
export const decrement = (): Action => ({ type: DECREMENT });
// Reducer函數(shù):根據(jù)派發(fā)的動(dòng)作更新?tīng)顟B(tài)
const counterReducer = (state = 0, action: Action): number => {
switch (action.type) {
case INCREMENT:
// 當(dāng)派發(fā)INCREMENT動(dòng)作時(shí),將當(dāng)前狀態(tài)加1
return state + 1;
case DECREMENT:
// 當(dāng)派發(fā)DECREMENT動(dòng)作時(shí),將當(dāng)前狀態(tài)減1
return state - 1;
case 'INCREMENTFIXED':
return state + 5;
default:
// 如果動(dòng)作類(lèi)型不被識(shí)別,則返回當(dāng)前狀態(tài)
return state;
}
};
// 將counterReducer作為模塊的默認(rèn)導(dǎo)出
export default counterReducer;
4、在index.tsx中引入
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
//引入redux
import { Provider } from 'react-redux';
import store from './store';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
reportWebVitals();
5、在components中創(chuàng)建Counter.tsx文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-818673.html
// src/components/Counter.tsx
import React from 'react';
import { connect } from 'react-redux';
import { increment, decrement } from '../store/reducers/counterReducer';
interface CounterProps {
count: number;
increment: () => void;
decrement: () => void;
}
const Counter: React.FC<CounterProps> = ({ count, increment, decrement }) => {
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
};
// 中間件mapStateToProps 函數(shù)將 Redux store 的狀態(tài)映射到組件的屬性。
const mapStateToProps = (state: { counter: number }) => ({
count: state.counter,
});
// 中間件mapDispatchToProps 對(duì)象將動(dòng)作創(chuàng)建函數(shù)映射到組件的屬性。
const mapDispatchToProps = {
increment,
decrement
};
// connect 函數(shù)將組件連接到 Redux store,并將 mapStateToProps 和 mapDispatchToProps 的結(jié)果傳遞給組件
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
示例效果圖:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-818673.html
到了這里,關(guān)于vue2(Vuex)、vue3(Pinia)、react(Redux)狀態(tài)管理的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!