vue3---pinia

目录

pinia的安装

在main.js中引入

pinia的创建

pinia的使用(一):

pinia的使用(二):

pinia的使用(三):$patch---$reset---$subscribe

pinia的使用(四):$onAction

插件


pinia的安装
yarn add pinia  /  npm install pinia
在main.js中引入

import { createApp } from "vue";
import App from "./App.vue";
import {createPinia} from 'pinia'
const pinia = createPinia()
createApp(App).use(pinia).mount("#app")
pinia的创建
import { defineStore } from "pinia";
import { ref } from 'vue'


// defineStore 的第一个参数为唯一ID  第二个参数可以是一个函数 也可以是一个对象
// 此方法类似于vue的vuex
export const useTextStore = defineStore("testStore", {
  // state 作为仓库的data
  state: () => ({
    counter: 12,
  }),
  // getters 作为商店的computed 属性
  getters: {
    double: (state) => state.counter * 2,
  },
  // actions 作为商店的methods 属性
  actions: {},
});


// 此方法类似于vue3的setup
export const useText1Store = defineStore("testStore1", () => {
  const counter = ref(50)
  const number = ref(100)
  // 调用其他store中的数据
  const Ustore = useTextStore()
  const doubleCounter = computed(() => counter.value * 2 + Ustore.counter);
  function getCounter() {
    counter.value++;
  }
  function getNumber() {
    number.value++;
  }

  return {
    counter,
    doubleCounter,
    getCounter,
    number,
    getNumber,
  };
});
pinia的使用(一):
<template>
  {{ store.counter }}
  {{ store.num }}
  {{ counter }}
</template>
<script>
import { storeToRefs } from 'pinia'
import { useTextStore, useText1Store } from '../store/index'
export default {
  setup() {
    const store = useTextStore()
    // store.counter  -- 0
    // store 是一个用 reactive 包裹的对象,这意味着不需要在 getter 之后写 .value 但是,就像 setup 中的 props 一样,我们不能解构它
    const store1 = useText1Store()
    // 无法解构,会破坏反应性
    // const { counter, doubleCounter } = store1

    // 当想使用解构的方法拿到store并具有响应式 要使用 storeToRefs
    const { counter, doubleCounter } = storeToRefs(store1)
    const { getCounter } = store1
    setTimeout(() => {
      store.counter++
      store.num = 2
    },1000)

    getCounter() // 在未使用storeToRefs依然是1  ,使用后变成响应式

    setTimeout(() => {
      store.$reset() // 使store里的值变成初始值
    },2000)
    
    return {
      store,
      counter, // 不会发生变化
      doubleCounter // 不会发生变化
    }
  }
}
</script>
<template>
  {{ number }}-- {{ counter }}-- {{ doubleCounter }}
  <div style="width:30px;height: 30px;background: red" @click="fn1"></div>
</template>
<script setup>
import { storeToRefs } from 'pinia'
import { useTextStore, useText1Store } from '../store/index'

const store1 = useText1Store()
const { counter, doubleCounter, number } = storeToRefs(store1)
const { getCounter, getNumber } = store1
getCounter()
const fn1 = () => {
  getNumber()
}
</script>
pinia的使用(二):

Setup store 也可以依赖于全局提供的属性,比如路由。任何应用层面提供的属性都可以在 store 中使用 inject()

// APP.vue

import { ref, provide } from 'vue'
const hreoName = ref('失败的man')
provide('hreoName', hreoName)



// test2.js
import { defineStore } from "pinia";
import { useRoute } from 'vue-router'
import { inject } from "vue";

export const useProjectStore = defineStore("testStore1", () => {
  const route = useRoute();
  const name = inject("hreoName");
  return {
    route,
    name
  };  
});

// test2.vue
<template>
  {{ store.name }}
</template>
<script setup>
import { computed } from 'vue'
import { useProjectStore } from '../store/index'
const store = useProjectStore()
</script>
pinia的使用(三):$patch---$reset---$subscribe

        $patch:方法是用于局部更新状态的方法。它允许您通过传递一个包含要更新的属性的对象来更新状态。可用于批量修改数据。

        $reset:

                1. $reset是pinia中的静态方法,它用于清空当前的响应式状态,当我们需要在组件中重置状态的时候就可以使用$reset
                2. 参数: 1.target 可选 定义要重置目标状态对象 2. options 可选,定义重置选项,如回调函数过渡动画
                3. 其参数有以下用途:

                        ①. 重置特定状态:当我们需要在组件中根据不同场景切换状态时,可以使用 $reset 方法清空当前状态,以便重新设置新的状态。
                        ②.初始化状态:在组件初始化时,可以使用 $reset 方法将状态重置为初始值,以便进行后续操作。
                        ③.清除副作用:当组件中的状态受到副作用影响时,可以使用 $reset 方法清除副作用,使状态恢复到正常状态。

        $subscribe:

                你可以通过 store 的 $subscribe() 方法侦听 state 及其变化。比起普通的 watch(),使用 $subscribe() 的好处是 subscriptions 在 patch 后只触发一次

// vue3中setup pinia无法使用$reset 需要在main.js重写
pinia.use(({ store }) => {
  const initialState = JSON.parse(JSON.stringify(store.$state));
  store.$reset = () => {
    store.$patch(initialState);
  };
});


// 使用
<template>
  {{ store1.number }}-- {{ store1.counter }}-- {{ store1.doubleCounter }}
  <div style="height: 30px;border: 1px solid #000" @click="fn1">点击变更状态</div>
  <div style="height: 30px;border: 1px solid #000" @click="fn2">点击还原状态</div>
</template>
<script setup>
import { storeToRefs } from 'pinia'
import { useTextStore, useText1Store } from '../store/index'

const store1 = useText1Store()
const { getCounter, getNumber } = store1
getCounter()
const fn1 = () => {
  store1.$patch({
    number: 10,
    counter: store1.counter++,
  })
}
const fn2 = () => {
  store1.$reset()
}
</script>
<template>
  {{ store1.number }}-- {{ store1.counter }}-- {{ store1.doubleCounter }}
  <div style="height: 30px;border: 1px solid #000" @click="fn1">点击变更状态</div>
</template>
<script setup>
import { storeToRefs } from 'pinia'
import { useTextStore, useText1Store } from '../store/index'

const store1 = useText1Store()
const { getCounter, getNumber } = store1
getCounter()

const fn1 = () => {
  store1.$patch({
    number: 10,
    counter: store1.counter++,
  })
}
// 监听 $patch
store1.$subscribe((mutation, state) => {
  console.log(mutation, state);

  // 每当状态发生变化时,将整个 state 持久化到本地存储。
  localStorage.setItem('cart', JSON.stringify(state))
},{ detached: true })
// 默认情况下,state subscription 会被绑定到添加它们的组件上 (如果 store 在组件的 setup() 里面)。这意味着,当该组件被卸载时,它们将被自动删除。如果你想在组件卸载后依旧保留它们,请将 { detached: true } 作为第二个参数,以将 state subscription 从当前组件中分离:
</script>
pinia的使用(四):$onAction

        通过 store.$onAction() 来监听 action 和它们的结果。传递给它的回调函数会在 action 本身之前执行。after 表示在 promise 解决之后,允许你在 action 解决后执行一个回调函数。同样地,onError 允许你在 action 抛出错误或 reject 时执行一个回调函数。这些函数对于追踪运行时错误非常有用

const unsubscribe = someStore.$onAction(
  ({
    name, // action 名称
    store, // store 实例,类似 `someStore`
    args, // 传递给 action 的参数数组
    after, // 在 action 返回或解决后的钩子
    onError, // action 抛出或拒绝的钩子
  }) => {
    // 为这个特定的 action 调用提供一个共享变量
    const startTime = Date.now()
    // 这将在执行 "store "的 action 之前触发。
    console.log(`Start "${name}" with params [${args.join(', ')}].`)

    // 这将在 action 成功并完全运行后触发。
    // 它等待着任何返回的 promise
    after((result) => {
      console.log(
        `Finished "${name}" after ${
          Date.now() - startTime
        }ms.\nResult: ${result}.`
      )
    })

    // 如果 action 抛出或返回一个拒绝的 promise,这将触发
    onError((error) => {
      console.warn(
        `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
      )
    })
  },
  true
  // 默认情况下,action 订阅器会被绑定到添加它们的组件上(如果 store 在组件的 setup() 内)。这意味着,当该组件被卸载时,它们将被自动删除。如果你想在组件卸载后依旧保留它们,请将 true 作为第二个参数传递给 action 订阅器,以便将其从当前组件中分离
)

// 手动删除监听器
unsubscribe()
插件

        Pinia store 现在可支持扩展: 

                1. 为 store 添加新的属性

                2. 定义 store 时增加新的选项

                3. 为 store 增加新的方法

                4. 包装现有的方法

                5. 改变甚至取消 action

                6. 实现副作用,如本地存储

                7. 仅应用插件于特定 store

        Pinia插件是一个函数,可以选择性地返回要添加到 store 的属性。它接收一个可选参数,即 context

export function myPiniaPlugin(context) {
  context.pinia // 用 `createPinia()` 创建的 pinia。 
  context.app // 用 `createApp()` 创建的当前应用(仅 Vue 3)。
  context.store // 该插件想扩展的 store
  context.options // 定义传给 `defineStore()` 的 store 的可选对象。
  // ...
}
        一、拓展Store

        可以直接通过在一个插件中返回包含特定属性的对象来为每个 store 都添加上特定属性:     

pinia.use(() => ({ hello: 'world' }))

        也可以直接在 store 上设置该属性,如果想被devtools 自动追踪请使用返回对象的方法

pinia.use(({ store }) => {
  store.hello = 'world'
})

        任何由插件返回的属性都会被 devtools 自动追踪,所以如果你想在 devtools 中调试 hello 属性,为了使 devtools 能追踪到 hello,请确保在 dev 模式下将其添加到store._customProperties 中

pinia.use(({ store }) => {
  store.hello = 'world'
  // 确保你的构建工具能处理这个问题,webpack 和 vite 在默认情况下应该能处理。
  if (process.env.NODE_ENV === 'development') {
    // 添加你在 store 中设置的键值
    store._customProperties.add('hello')
  }
})

        每个 store 都被 reactive包装过,所以可以自动解包任何它所包含的ref,所以在下列示例中不需要.value 去获取变量的数值

const sharedRef = ref('shared')
pinia.use(({ store }) => {
  // 每个 store 都有单独的 `hello` 属性
  store.hello = ref('secret')
  // 它会被自动解包
  store.hello // 'secret'

  // 所有的 store 都在共享 `shared` 属性的值
  store.shared = sharedRef
  store.shared // 'shared'
})
        二、添加新的 state

        给 store 添加新的 state 属性或者在服务端渲染的激活过程中使用的属性,你必须同时在两个地方添加它,并且使用响应式的API让其能够在多个组件中共享相同的数据。

        ①:在 store 上,然后你才可以用 store.myState 访问它

        ②:在 store.$state 上,然后你才可以在 devtools 中使用它,并且,在 SSR 时被正确序列化

import { toRef, ref } from 'vue'

pinia.use(({ store }) => {
  if (!Object.prototype.hasOwnProperty(store.$state, 'hasError')) {
    // 在插件中定义 hasError,因此每个 store 都有各自的
    // hasError 状态
    const hasError = ref(false)
    store.$state.hasError = hasError
  }
  store.hasError = toRef(store.$state, 'hasError')
  // 在这种情况下,最好不要返回 `hasError`
  // 因为它将被显示在 devtools 的 `state` 部分
  // 如果我们返回它,devtools 将显示两次。
})
        三、添加新的外部属性

        当添加外部属性、第三方库的类实例或非响应式的简单值时,你应该先用 markRaw() 来包装一下它,再将它传给 pinia

import { markRaw } from 'vue'
import { router } from './router'

pinia.use(({ store }) => {
  store.router = markRaw(router)
})
        四、在插件中调用 $subscribe
pinia.use(({ store }) => {
  store.$subscribe(() => {
    // 响应 store 变化
  })
  store.$onAction(() => {
    // 响应 store actions
  })
})
        五、添加新的选项

        在定义 store 时,可以创建新的选项,以便在插件中使用它们。例如,你可以创建一个 debounce 选项,允许你让任何 action 实现防抖

defineStore('search', {
  actions: {
    searchContacts() {
      // ...
    },
  },

  // 这将在后面被一个插件读取
  debounce: {
    // 让 action searchContacts 防抖 300ms
    searchContacts: 300,
  },
})

        该插件可以读取该选项来包装 action,并替换原始 action:

// 使用任意防抖库
import debounce from 'lodash/debounce'

pinia.use(({ options, store }) => {
  if (options.debounce) {
    // 我们正在用新的 action 来覆盖这些 action
    return Object.keys(options.debounce).reduce((debouncedActions, action) => {
      debouncedActions[action] = debounce(
        store[action],
        options.debounce[action]
      )
      return debouncedActions
    }, {})
  }
})

        注意,在使用 setup 语法时,自定义选项作为第 3 个参数传递:

defineStore(
  'search',
  () => {
    // ...
  },
  {
    // 这将在后面被一个插件读取
    debounce: {
      // 让 action searchContacts 防抖 300ms
      searchContacts: 300,
    },
  }
)

Vue 3中,`pinia-plugin-persistedstate`是一个用于持久化状态的Pinia插件,它允许你在用户关闭和重新打开应用时保存和恢复数据。关于设置Pinia状态的时效,你需要明确你是指的状态持久化的时间范围,例如: 1. **默认保存间隔**:这个插件通常会自动保存状态到浏览器的localStorage或 sessionStorage中。默认情况下,Pinia-PersistedState可能没有特定的保存间隔,但你可以通过配置自定义保存策略。 2. **手动触发保存**:你可以选择在特定场景(如组件卸载或页面刷新前)调用保存方法,这可以让你控制保存的时机。 3. **失效时间**:对于敏感信息,你可能希望设置一个过期时间,超过这个时间后数据会被清除。这通常不是由Pinia-PersistedState直接处理,而是通过在存储选项中设置`maxAge`属性来实现,然后在加载数据时检查是否已过期。 为了具体设置pinia状态的时效,你需要在配置插件时进行以下操作: ```javascript import { createApp } from 'vue'; import { useStore } from '@pinia/core'; import { persistedState } from 'pinia-plugin-persistedstate'; const store = defineStore('myStore', { // ...定义你的状态和方法 }); // 使用 persistedState 插件 createApp({ // ...其他配置 }) .use(store) .use(persistedState, { key: 'myStore', // 存储的键名 // 可选的保存策略,如自动保存间隔、过期时间等 // 例如: // localStorage: { maxAge: 24 * 60 * 60 * 1000 }, // 一天后数据过期 }); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值