pinia学习笔记

1、创建项目(vite+vue+ts)

pnpm create vite

2、安装pinia

yarn add pinia

3、使用

1、引入注册main.ts

import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
const pinia = createPinia()
const app=createApp(App)
app.use(pinia).mount('#app')

2、初始化仓库Store(存储是使用定义的defineStore(),并且它需要一个唯一的名称,作为第一个参数传递)

新建store/main.ts

import { defineStore } from  'pinia'

export const mainStore = defineStore('main',{
    state:()=>{
        return {
            count:100,
            price:250
        }
    },
    getters:{
        doubleCount():number{
            return this.count*2
        },
        doublePrice():number{
            return this.price*2
        }
    },
    actions:{
        changeStoreData(){
            this.count+=1
            this.price+=1
        },
    }
})

3、页面使用

pinia学习笔记_第1张图片

 

 





4、actions(异步及调用其他actions方法) 

新建store/use.ts模块

import { defineStore } from  'pinia'
import { ElLoading } from 'element-plus'
type Res = {
    nickname:string,
    age:number
}
const Login = ()=>{
    return new Promise((resolve,reject)=>{
        const loading = ElLoading.service({
            lock: true,
            text: 'Loading',
            background: 'rgba(0, 0, 0, 0.7)',
          })
        setTimeout(() => {
            resolve({
                nickname:'张三',
                age:22
            })
            loading.close()
        }, 5000);
    })
}
export const userStore = defineStore('user',{
    state:()=>{
        return {
           nickname:'',
           age:0
        }
    },
    getters:{
        
    },
    actions:{
        async getUserInfo(){
            const res = await Login();
            this.nickname=res.nickname;
            //this.age=res.age;
            //调用其他actions
            this.setAge(res.age)
        },
        setAge(age:number){
            this.age=age
        }
    }
})


5、getters (主要作用类似于computed 数据修饰并且有缓存)

getters 可以互相调用 普通函数形式可以使用this 使用箭头函数不能使用this this指向已经改变指向undefined 修改值请用state

  getters:{
        doubleCount():number{
            //return this.count*2
            return this.doublePrice*2
        },
        doublePrice:(state)=>state.price*2
    },

6、 常用api

1、$reset(重置store到他的初始状态)

  重置数据
const resetData =()=>{
  main.$reset()
}

 2、订阅state改变(类似于Vuex 的abscribe  只要有state 的变化就会走这个函数)

main.$subscribe((args,state)=>{
  console.log(args,state,'数据改变')
})

第二个参数

如果你的组件卸载之后还想继续调用请设置第二个参数

main.$subscribe((args,state)=>{
  console.log(args,state,'数据改变')
},{
  detached:true
})

3、订阅Actions的调用(只要有actions被调用就会走这个函数)

main.$onAction((args)=>{
   console.log(args,'action调用'); 
})

pinia学习笔记_第2张图片

7、 pinia插件 --数据持久化

1、安装

cnpm i pinia-plugin-persist --save

2、新建store/index.ts

import { createPinia } from 'pinia'
//pinia 持久化插件
import piniaPluginPersist from 'pinia-plugin-persist'
const store = createPinia()
store.use(piniaPluginPersist)
export default store

3、修改main.ts

import { createApp } from 'vue'
import App from './App.vue'

import 'element-plus/dist/index.css'
import store from './store/index';
import piniaPluginPersist from 'pinia-plugin-persist';
store.use(piniaPluginPersist)
const app=createApp(App)
app.use(store).mount('#app')

4、保存nickname,修改store/user.ts

import { defineStore } from  'pinia'
import { ElLoading } from 'element-plus'
type Res = {
    nickname:string,
    age:number
}
const Login = ()=>{
    return new Promise((resolve,reject)=>{
        const loading = ElLoading.service({
            lock: true,
            text: 'Loading',
            background: 'rgba(0, 0, 0, 0.7)',
          })
        setTimeout(() => {
            resolve({
                nickname:'张三',
                age:22
            })
            loading.close()
        }, 5000);
    })
}
export const userStore = defineStore('user',{
    state:()=>{
        return {
           nickname:'',
           age:0
        }
    },
    getters:{
        
    },
    actions:{
        async getUserInfo(){
            const res = await Login();
            this.nickname=res.nickname;
            //this.age=res.age;
            //调用其他actions
            this.setAge(res.age)
        },
        setAge(age:number){
            this.age=age
        }
    },
    persist:{
        enabled:true,
        strategies:[
            {
                storage:localStorage,paths:['nickname']
            }
        ]
    }
})

pinia学习笔记_第3张图片

 4、购物车案例

pinia学习笔记_第4张图片

 

1、新建src/api/shop.ts

/**
 * src/api/shop.ts
 * Mocking client-server processing
 */
 export interface IProduct {
    id: number
    title: string
    price: number
    inventory: number // 库存
  }
  
  const _products: IProduct[] = [
    {id: 1, title: 'iPad 4 Mini', price: 500.01, inventory: 2},
    {id: 2, title: 'H&M T-Shirt White', price: 10.99, inventory: 10},
    {id: 3, title: 'Charli XCX -Sucker CD', price: 19.99, inventory: 5}
  ]
  
  export const getProducts = async () => {
    await wait(1000)
    return _products
  }
  
  export const buyProducts = async () => {
    await wait(1000)
    return Math.random() > 0.5
  }
  
  /**
   * 封装了Promise版本的定时器
   * @param delay 延迟时间
   * @returns Promise
   */
  async function wait(delay:number) {
    return new Promise(resolve => setTimeout(resolve, delay))
  }

2、新建components/ProductList.vue




3、新建components/Cart.vue



4、组件在App.vue中引用






5、新建store/products.ts

import { defineStore } from "pinia"
import { getProducts, IProduct } from "../api/shop"

export const useProdunctsStore = defineStore('products', {
  state: () => {
    return {
      all: [] as IProduct[] // 所有商品列表(学习类型断言的使用)
    }
  },

  getters: {}, 

  actions: {
    //actions既支持异步操作
    async loadAllProducts() {
      const ret = await getProducts()
      this.all = ret
    },
    // 也支持同步操作
    decrementProduct(product: IProduct) {
      const ret = this.all.find(item => item.id === product.id)
      if (ret) {
        ret.inventory--
      }
    }
  }
})

6、新建store/cart.ts

import { defineStore } from "pinia";
import { buyProducts, IProduct } from "../api/shop";
import { useProdunctsStore } from "./products";

/**
 * {id, title, price, quantity}
 */
type CartProduct = { // 合并
  num: number
} & Omit // Omit是过滤

export const useCartStore = defineStore('cart', {
  state: () => {
    return {
      cartProducts: [] as CartProduct[],
      checkoutStatus: null as null | string
    }
  },

  getters: {
    // 总价
    totalPrice(state) {
      return state.cartProducts.reduce((total, item) => {
        return total + item.price * item.num
      }, 0)
    }
  },

  actions: {
    /**
     * 往购物车添加商品
     * 这是一个相对复杂的逻辑,与容器中的数据强相关,所以肯定要定义在actions里面!
     * @param product 需要添加的商品
     */
    addProductToCart(product: IProduct) {
      // 先看商品有没有库存
      if (product.inventory <= 0) {
        return
      }
      // 检查购物车中是否已有该商品
      
      const cartItem = this.cartProducts.find(item => item.id === product.id)
      // 如果有则让商品数量+1
      if (cartItem) {
        cartItem.num++
      } else {
        // 如果没有则添加到购物车列表中
        this.cartProducts.push({
          id: product.id,
          title: product.title,
          price: product.price,
          num: 1
        })
      }

      // 跟新商品库存(应该由商品容器暴露API)
      const productsStore = useProdunctsStore()
      productsStore.decrementProduct(product)
      // 跨容器通信!!!!!竟然如此简单!!!
    },
    /**
     * 结算
     */
    async checkOut() {
      const ret = await buyProducts() 
      this.checkoutStatus = ret ? '成功' : '失败'
      if (ret) {
        this.cartProducts = [] // 清空购物车
      }
    }
  }
})

你可能感兴趣的:(学习,typescript,javascript)