likes
comments
collection
share

pinia之前的vuex前段时间介绍了一下组件通信的部分父子组件之间的通信,今天就来给大家分享一个任何组件之间的通信方法

作者站长头像
站长
· 阅读数 19

前段时间介绍了一下组件通信的部分父子组件之间的通信,今天就来给大家分享一个任何组件之间的通信方法,这个方法就是vuex。它就不再仅仅局限于父子组件的通信了,而是全局的状态共享,任何组件都能够使用到它里面的数据。

什么是vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式与库。这么说可能有点晕,简单的理解就是实现组件间数据共享的一种方式,就类似于一个数据仓库,组件需要数据直接去取就行了。

vuex的核心概念

1. state

state代表了应用程序的状态或数据,这些数据会被多个组件所共享,就相当于一个数据存储容器,但是我们只能访问这里面的数据,并不能直接修改state里面的内容,而是要通过Mutations来修改数据内容,这也是唯一一个修改数据状态的方法。我们在state里面可以定义简单的一些数据,如果数据较多的话,我们可以使用model来模块状态。简单的数据状态具体表示如下:

state:{
    count:0
  },

2. mutations

这是更改状态的唯一途径,同时也保证了状态更改的可追踪性和可预测性。但是它必须是一个同步函数,也就是说它不能进行复杂的计算,如从中向后端获取数据等异步的操作,他必须是一个有明确且清晰的状态修改规定。所以我们通常用actions来进行复杂的操作,然后通过commit提交一个mutation。当然我们也可以在任何一个地方通过this.store.commit来提交。如:

const mutations = {
    setProducts(state,products){
        state.all = products
    }
}

这里面的setProducts就是我们通过commit提交的mutation名称。

3. actions

actions类似于mutations,但是他提交的是mutations,而不能直接来修改数据状态,还是要通过mutations来修改状态。另外他可以进行任意的异步操作。如果我们需要进行修改状态,就可以在actions里面定义一个方法来实现这个修改状态。如:

const actions = {
    // api 请求 -> 提交mutations
    // commit vuex给actions可以commit mutations的API
    getAllProducts({commit}){
        API.getProducts((products)=>{
            console.log(products);
            commit('setProducts',products)  // 提交mutations 以及她的值
        })
    }
}

actions需要使用store.dispacth方法来进行触发,如

store.dispatch('products/getAllProducts')

这就表示我们在别的地方触发products这个store模块里的actions的getAllProducts这个方法。

4. getters

这类似于 Vue 的计算属性,Getters 接收 state 作为其第一个参数并返回处理后的数据,主要用于当需要让多个组件访问同一份状态时,避免在每个组件中重复定义计算属性。例如我们在完成一个购物车功能时,需要一个数据来记录购物车的总金额,如果我们重新定义一个状态的话就会出现数据杂糅的现象。我们可以在getters里面定义一个计算方法来计算总金额。如下:

 cartTotalPrice:(state,getters) => {
        return getters.cartProducts.reduce((total,product)=>{
            return total + product.price * product.quantity
        },0)
    }

5. model

这用来实现模块化状态,防止我们的应用太大时,store对象非常臃肿。这样我们就可以将其分割成一个个的小模块。

modules:{
    cart, // 购物车状态
    products  //商品状态
  }

怎么引入vuex

  1. 首先我们需要先下载vuex,通过npm install vuex
  2. 在全局注册这个组件,也就是app.use(store)
  3. 然后通过createStore返回一个单一状态树export default createStore(),状态就是树上的结点。

怎么使用vuex

我这里通过一个购物车功能来演示一下vuex的用法。

<template>
    <ul>
        <li
            v-for="product in products" 
            :key="product.id"
        >
            {{ product.title }}-{{ product.price }}
            <br>
            <button 
            :disabled="!product.inventory "
            @click="addProductToCart(product)">
                Add to Cart
            </button>

        </li>
    </ul>
</template>

<script setup>

import { computed,onMounted } from 'vue';
import {useStore} from 'vuex'

const store = useStore();
const products = computed(()=>store.state.products.all)
onMounted(()=>{
    store.dispatch('products/getAllProducts')  
})
const addProductToCart = (product)=>{
    // 修改状态 dispatch action -> commit mutation
    store.dispatch('cart/addProductToCart',product)
}

</script>

<style lang="scss" scoped>

</style>

这里我主要演示了dispatch来触发actions。

import { createStore } from 'vuex'
import cart from './modules/cart'
import products from './modules/products'


// 仓库 ,分个子仓
export default createStore({
  //全局状态  数据多就不好维护
  state:{
  },
  // 模块化状态  
  modules:{
    cart, // 购物车状态
    products  //商品状态
  }
})

这里主要就是模块化store,为了防止store变得过于臃肿。

const state = {
    items:[]
}

const getters = {
    cartProducts:(state,getters,rootState)=>{
        return state.items.map(({id,quantity})=>{
            const product = rootState.products.all.find(product => product.id===id)
            return {
                id: product.id,
                title: product.title,
                price: product.price,
                quantity: quantity
            }
        })
    },
    cartTotalPrice:(state,getters) => {
        return getters.cartProducts.reduce((total,product)=>{
            return total + product.price * product.quantity
        },0)
    }
}

const actions = {
    addProductToCart({commit,state}, product){
        if(product.inventory > 0){
            const cartItem = state.items.find(item => item.id===product.id)
            if(!cartItem) {
                // 如果购物车中没有该商品,则添加该商品
                commit('pushProductToCart',{id:product.id})
            }else{
                // 如果购物车中有该商品,则直接加一
                commit('incrementQuantity', cartItem)
            }
            commit('products/decrementProductInventory',{id:product.id},{root:product})
        }
    }
}

// 跟 state 的操作在这里  这就是比pinia复杂的地方
// 规定了数据可以怎么变化
// mutations 就是财务  对数据的修改原则
const mutations = {
    pushProductToCart(state,{ id }){
        state.items.push({
            id,
            quantity:1
        })
    },
    incrementQuantity(state,cartItem){
        cartItem.quantity++
    }
}


// store.product.all
export default {
    namespaced:true,
    state,
    getters,
    actions,
    mutations
}

这是cart模块的store,这里的getters用来进行数据的计算,actions对数据进行操作,之后提交为mutation,交给mutations修改它的状态。

总结

为了减少文章篇幅,我仅仅是拿出了几个文件来介绍vuex的使用,大家可以自行看我提供的部分代码,相信大佬们可以很快就能弄清楚具体的用法。vuex它适合大型的项目,用来进行数据管理,这样的数据管理更严格,因为他就只有mutations能够修改状态,通过commit提交修改。但是这样工序也是比较复杂的,所以现在又有一个新的方法来实现数据管理功能了,那就是pinia。pinia在vue3 推出 hooks,更方便,而且它自带模块化,没有mutations,数据管理更加的自由。

pinia之前的vuex前段时间介绍了一下组件通信的部分父子组件之间的通信,今天就来给大家分享一个任何组件之间的通信方法

转载自:https://juejin.cn/post/7402079591717978146
评论
请登录