Vuex状态管理

一.Vuex是什么?为什么要使用它?

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

大家可以思考一下,​JavaScript开发的应用程序,已经变得越来越复杂了.JavaScript需要管理的状态越来越多,越来越复杂:

  • 这些状态包括服务器返回的数据、缓存数据、用户操作产生的数据等等;
  • 也包括一些UI的状态,比如某些元素是否被选中,是否显示加载动效,当前分页;
    然而,当我们有多个组件共享一个共同的状态时,就没有这么简单了:单向数据流的简洁性很容易被破坏:
  1. 多个视图依赖于同一状态;
  2. 来自不同视图的行为需要变更同一状态;
    因此vuex就是把组件共享状态抽取出来以一个全局单例模式管理,把共享的数据函数放进vuex中,任何组件都可以进行使用。

二.安装

使用npm或yarn安装

在这里插入# npm 安装
npm install vuex

# yarn 安装
yarn add vuex

三.配置

1.在src目录下创建一个store目录,在该目录下创建index.js文件,用于创建Store对象
在这里插入图片描述

//用于创建Vuex的核心对象Store
//1.导入
import {createStore } from 'vuex'


//2.创建Store对象
const store = createStore({
//state 用于存储数据
state(){
return {
count:1,
}
},
//actions 用于响应组件中的事件
actions:{

},
//mutations 用于操作数据
mutations:{

}
});


//3.暴露出store对象
export default store;

2.在main.js使用store对象

import store from './store';
app.use(store);

3.在Vue组件,可以通过this.$store 访问store实例

<template>
<h2>{{$store.state.count}}</h2>
</template>

<script>
export default {
name: 'App',
data() {
return {

};
},
components: {
},
methods: {

},
mounted() {
console.log(this.$store.state.count);
}
};
</script>

<style lang="css" scoped>
</style>

四.状态管理

4.1 State

提供唯一的公共数据源,所有共享的数据统一放到store的state进行储存,相似与data

在vuex中state中定义数据,可以在任何组件中进行调用

//1.导入createStore函数
import {createStore} from 'vuex'



//2.创建vuex的核心对象
//定义一个状态
const  state={
    count:0,
    user:{id:1,username:'zhangsan',age:21},
    username:'张三',
    orders:[{
        id:1,
        pname:'华为P40',
        price:3999,
        num:1,
    },{
        id:2,
        pname:'华为笔记本',
        price:4999,
        num:2,
    }]
}

调用:

方法一:

在标签中直接使用

在这里插入图片描述

方法二:
this.$store.state.count(全局数据名称)

方法三:
从vuex中按需导入mapstate函数

import { mapState } from “vuex”;

...mapState({
       count:state=>state.count*2,
       username:state=>state.username,

4.2. Moutation
​ 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:你可以向 store.commit 传入额外的参数,即 mutation 的载荷(payload)

在这里插入图片描述

你不能直接调用一个 mutation 处理函数。这个选项更像是事件注册:“当触发一个类型为 INCREMENT 的 mutation 时,调用此函数。”要唤醒一个 mutation 处理函数,你需要以相应的 type 调用 store.commit 方法:
.png&pos_id=img-gJTTX5sk-1721573256599)

在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读:

 increment:function(context,value){
            context.commit("INCREMENT",{
                value
            });
        },

INCREMENT(store,payload){
            store.sum +=payload.value;   
        },

提交 mutation 的另一种方式是直接使用包含 type 属性的对象:

store.commit({
  type: 'increment',
  amount: 10
})

当使用对象风格的提交方式,整个对象都作为载荷传给 mutation 函数,因此处理函数保持不变:

4.2.1 在组件中提交 Mutation

​ 你可以在组件中使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store

<template>
    <div class="box">
        <h2>和:{{$store.state.sum}} --{{count}}</h2>
        <input type="number" length="3" v-model="num"/>
        <input type="button" value="+" @click="add({value:num})"/>
        <input type="button" value="-" @click="sub({value:num})"/>
        <Counter/>
    </div>
</template>

<script>
import {mapMutations } from 'vuex'
export default {
    name: 'CalcSum',

    data() {
        return {
            num:1,
        };
    },

    mounted() {
        
    },
    methods: {
        /*
        add(){
            //通过dispatch去提交一个action
            this.$store.dispatch('increment', this.num);
            console.log(this.$store.state.sum)
            //强制刷新页面
            //this.$forceUpdate();
        },
        sub(){
            this.$store.dispatch('decrement', this.num);
            //this.$forceUpdate();
        },*/
        
        ...mapMutations({
            add:'INCREMENT',
            sub:'DECREMENT'
        }),
    },
    computed: {
        count () {
             return this.$store.state.sum
        }
    }
};
</script>

<style lang="css" scoped>
    .box{
        width:70%;
        margin: auto;
    }
</style>

如果组件的事件函数名与Mutation中修改状态的函数名一样,我们可以简写:

...mapMutations(['INCREMENT','DECREMENT']),

mutation重要原则:

​ 一条重要的原则就是要记住 mutation 必须是同步函数,这是因为devtool工具会记录mutation的日记;每一条mutation被记录,devtools都需要捕捉到前一状态和后一状态的快照;但是在mutation中执行异步操作,就无法追踪到数据的变化;
​ 所以Vuex的重要原则


4.3.Action
​ 如果我们希望在Vuex中发送网络请求的话需要如何操作呢?那我们就使用Action

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

让我们来注册一个简单的 action:

const store = createStore({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.statecontext.getters 来获取 state 和 getters。当我们在之后介绍到 Modules 时,你就知道 context 对象为什么不是 store 实例本身了。

4.3.1actions的分发操作

如何使用action呢?进行action的分发:

  • 分发使用的是 store 上的dispatch函数;

在这里插入图片描述

  • 同样的,它也可以携带我们的参数:

在这里插入图片描述

  • 也可以以对象的形式进行分发:

    在这里插入图片描述

乍一眼看上去感觉多此一举,我们直接分发 mutation 岂不更方便?实际上并非如此,还记得 mutation 必须同步执行这个限制么?Action 就不受约束!我们可以在 action 内部执行异步操作:

4.3.2 actions的辅助函数

action也有对应的辅助函数:使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用(需要先在根节点注入 store

在这里插入图片描述

4.4 Getter

某些属性我们可能需要经过变化后来使用,这个时候可以使用getters:Vuex 允许我们在 store 中定义“getters”(可以认为是 store 的计算属性)

在这里插入图片描述

上图我们中函数Getter 接受 state 作为其第一个参数:

 getters:{
        totalPrice(state){
            let total= 0;
            state.books.forEach((book)=>{
                total += book.count*book.price;
            })

            return total;
        }
    },

我们在其他组件可以访问Getter 对象,Getter 会暴露为 store.getters 对象,你可以以属性的形式访问这些值:

 <div>
     <h2>总价:{{$store.getters.totalPrice}}</h2>
</div>

getters可以接收第二个参数

 getters:{
        totalPrice(state,getters){
            let total= 0;
            state.books.forEach((book)=>{
                total += book.count*book.price;
            })

            return total+","+getters.myName;
        },
        myName(state){
            return state.name;
        }
    },

你也可以通过让 getter 返回一个函数,来实现给 getter 传参。在你对 store 里的数组进行查询时非常有用。

 getters:{
        totalPrice(state,getters){
            let total= 0;
            state.books.forEach((book)=>{
                total += book.count*book.price;
            })

            return total+","+getters.myName;
        },
        myName(state){
            return state.name;
        },
        getBookById(state){
            return (id)=>{
                return state.books.find(book=>
                    book.id === id
                );
            }
        }
    },

访问:

<h2>书籍信息:{{$store.getters.getBookById(3)}}</h2>

4.4.1 mapGetters 辅助函数

mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:

<template>
    <div>
        <h2>总价:{{totalPrice}}</h2>
        <h2>书籍信息:{{getBookById(3)}}</h2>
    </div>
</template>

<script>
import { mapGetters } from 'vuex'
export default {
    name: 'Book',
    computed:{
        ...mapGetters(['totalPrice','getBookById']),
    },
};
</script>

<style lang="scss" scoped>

</style>

  • 30
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值