Pinia知识点(vue3版本)

    • 为什么要使用 Pinia?


  • Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。

  • Pinia的好处:

1.dev-tools支持
跟踪动作,突变的时间线
Store出现在使用他们的组件中
time travel 和 更容易的调试
2.热模块更换
在不重新加载页面的情况下修改您的 Store
在开发时保持任何现有状态
3.插件
使用插件扩展 Pinia 功能
4.为 JS 用户提供适当的 TypeScript 支持或 autocompletion
5.服务器端渲染支持
    • 与Vuex的比较

    • 与Vuex相比,pinia提供了更简单的API,更少的规范,提供了 Composition-API 风格的 API,最重要的是,在与 TypeScript 一起使用时具有可靠的类型推断支持。

    • mutations 不再存在。他们经常被认为是 非常 冗长。他们最初带来了 devtools 集成,但这不再是问题。
    • 与 Vuex 3.x/4.x 的比较

    • mutations 不再存在。他们经常被认为是 非常 冗长。他们最初带来了 devtools 集成,但这不再是问题。
    • 不再需要注入、导入函数、调用函数
    • 安装Pinia

    • 安装:npm i pinia
    • 创建pinia(根存储)并且全局都能使用
import { createPinia } from 'pinia'

app.use(createPinia())

什么是 Store

    • 什么是Store

    • 简单来说就是 托管全局状态 一个任何人都能读取和写入的组件

    • 定义一个Store

  1. Store 是使用 defineStore() 定义的,并且它需要一个唯一名称,作为第一个参数传递

import { defineStore } from 'pinia'

// useStore 可以是 useUser、useCart 之类的任何东西
// 第一个参数是应用程序中 store 的唯一 id
export const useStore = defineStore('main', {
  // other options...
})

//这个 name,也称为 id,是必要的,Pinia 使用它来将 store 连接到 devtools。 将返回的函数命名为 use... 是跨可组合项的约定
  1. 定义 一个 store,因为在 setup() 中调用 useStore() 之前不会创建 store

import { useStore } from '@/stores/counter'

export default {
  setup() {
    const store = useStore()

    return {
      // 可以返回整个 store 实例以在模板中使用它
      store,
    }
  },
}
//可以根据需要定义任意数量的 store 在不同的文件中定义每个 store  充分利用pinia
//store 被实例化 可以直接在 store 上访问 state、getters 和 actions 中定义的任何属性

3.从 Store 中提取属性同时保持其响应式,需要使用storeToRefs()。 它为任何响应式属性创建 refs。 当使用 store 中的状态但不调用任何操作

import { storeToRefs } from 'pinia'

export default defineComponent({
  setup() {
    const store = useStore()
    // `name` 和 `doubleCount` 是响应式引用
    // 这也会为插件添加的属性创建引用
    // 但跳过任何 action 或 非响应式(不是 ref/reactive)的属性
    const { name, doubleCount } = storeToRefs(store)

    return {
      name,
      doubleCount
    }
  },
})

State

  1. state 是 store 的核心部分

import { defineStore } from 'pinia'

const useStore = defineStore('storeId', {
  // 推荐使用 完整类型推断的箭头函数
  state: () => {
    return {
      // 所有这些属性都将自动推断其类型
      counter: 0,
      name: 'Eduardo',
      isAdmin: true,
    }
  },
})

2.访问state

const store = useStore()

store.counter++
//通过 store 实例访问状态来直接读取和写入状态

3.重置状态

const store = useStore()

store.$reset()
//通过调用 store 上的 $reset() 方法将状态 重置 到其初始值

4.使用选项API

// Example File Path:
// ./src/stores/counterStore.js

import { defineStore } from 'pinia',

const useCounterStore = defineStore('counterStore', {
  state: () => ({
    counter: 0
  })
})

5.使用 setup( )

import { useCounterStore } from '../stores/counterStore'

export default {
  setup() {
    const counterStore = useCounterStore()

    return { counterStore }
  },
  computed: {
    tripleCounter() {
      return counterStore.counter * 3
    },
  },
}
//setup() 钩子可以使在 Options API 中使用 Pinia 不需要额外的 map helper

6.不使用 setuo( )

import { mapState } from 'pinia'
import { useCounterStore } from '../stores/counterStore'

export default {
  computed: {
    // 允许访问组件内部的 this.counter
    // 与从 store.counter 读取相同
    ...mapState(useCounterStore, {
      myOwnName: 'counter',
      // 您还可以编写一个访问 store 的函数
      double: store => store.counter * 2,
      // 它可以正常读取“this”,但无法正常写入...
      magicValue(store) {
        return store.someGetter + this.counter + this.double
      },
    }),
  },
}
//不使用 Composition API,并且使用的是 computed、methods、...,则可以使用 mapState() 帮助器将状态属性映射为只读计算属性

7.可修改状态

import { mapWritableState } from 'pinia'
import { useCounterStore } from '../stores/counterStore'

export default {
  computed: {
    // 允许访问组件内的 this.counter 并允许设置它
    // this.counter++
    // 与从 store.counter 读取相同
    ...mapWritableState(useCounterStore, ['counter'])
    // 与上面相同,但将其注册为 this.myOwnName
    ...mapWritableState(useCounterStore, {
      myOwnName: 'counter',
    }),
  },
}
//想写入一些状态属性,可以使用 mapWritableState() 代替

8.替换state

store.$state = { counter: 666, name: 'Paimon' }
//通过将其 $state 属性设置为新对象来替换 Store 的整个状态

Getters

  1. Getter 完全等同于 Store 状态的计算值

export const useStore = defineStore('main', {
  state: () => ({
    counter: 0,
  }),
  getters: {
    doubleCount: (state) => state.counter * 2,
  },
})
//可以用 defineStore() 中的 getters 属性定义 接收“状态”作为第一个参数以鼓励箭头函数的使用

2.直接在 store 实例上访问 getter

<template>
  <p>Double count is {{ store.doubleCount }}</p>
</template>

<script>
export default {
  setup() {
    const store = useStore()

    return { store }
  },
}
</script>

3.访问其他 getter

export const useStore = defineStore('main', {
  state: () => ({
    counter: 0,
  }),
  getters: {
    // 类型是自动推断的,因为我们没有使用 `this`
    doubleCount: (state) => state.counter * 2,
    // 这里需要我们自己添加类型(在 JS 中使用 JSDoc)。 我们还可以
    // 使用它来记录 getter
    /**
     * 返回计数器值乘以二加一。
     *
     * @returns {number}
     */
    doubleCountPlusOne() {
      // 自动完成 ✨
      return this.doubleCount + 1
    },
  },
})
//与计算属性一样,可以组合多个 getter。 通过 this 访问任何其他 getter

4.将参数传递给 getter

export const useStore = defineStore('main', {
  getters: {
    getUserById: (state) => {
      return (userId) => state.users.find((user) => user.id === userId)
    },
  },
})
//Getters 只是幕后的 computed 属性,因此无法向它们传递任何参数。 可以从 getter 返回一个函数以接受任何参数

在组件中使用

<script>
export default {
  setup() {
    const store = useStore()

    return { getUserById: store.getUserById }
  },
}
</script>

<template>
  <p>User 2: {{ getUserById(2) }}</p>
</template>

5.访问其他Store的getter

import { useOtherStore } from './other-store'

export const useStore = defineStore('main', {
  state: () => ({
    // ...
  }),
  getters: {
    otherGetter(state) {
      const otherStore = useOtherStore()
      return state.localData + otherStore.data
    },
  },
})
//要使用其他存储 getter,可以直接在 better 内部使用它

6.与 setup( )一起使用

export default {
  setup() {
    const store = useStore()

    store.counter = 3
    store.doubleCount // 6
  },
}
//可以直接访问任何 getter 作为 store 的属性(与 state 属性完全一样)

7.使用选项API

使用 setup( )

import { useCounterStore } from '../stores/counterStore'

export default {
  setup() {
    const counterStore = useCounterStore()

    return { counterStore }
  },
  computed: {
    quadrupleCounter() {
      return counterStore.doubleCounter * 2
    },
  },
}

没有 setup( )

import { mapState } from 'pinia'
import { useCounterStore } from '../stores/counterStore'

export default {
  computed: {
    // 允许访问组件内的 this.doubleCounter
    // 与从 store.doubleCounter 中读取相同
    ...mapState(useCounterStore, ['doubleCount'])
    // 与上面相同,但将其注册为 this.myOwnName
    ...mapState(useCounterStore, {
      myOwnName: 'doubleCounter',
      // 您还可以编写一个访问 store 的函数
      double: store => store.doubleCount,
    }),
  },
}
//可以使用 previous section of state 中使用的相同 mapState() 函数映射到 getter

Actions

1.Actions 相当于组件中的 methods

export const useStore = defineStore('main', {
  state: () => ({
    counter: 0,
  }),
  actions: {
    increment() {
      this.counter++
    },
    randomizeCounter() {
      this.counter = Math.round(100 * Math.random())
    },
  },
})
//可以使用 defineStore() 中的 actions 属性定义

2.actions 可以是异步的,您可以在其中await 任何 API 调用甚至其他操作

import { mande } from 'mande'

const api = mande('/api/users')

export const useUsers = defineStore('users', {
  state: () => ({
    userData: null,
    // ...
  }),

  actions: {
    async registerUser(login, password) {
      try {
        this.userData = await api.post({ login, password })
        showTooltip(`Welcome back ${this.userData.name}!`)
      } catch (error) {
        showTooltip(error)
        // 让表单组件显示错误
        return error
      }
    },
  },
})

3.自由地设置你想要的任何参数并返回任何东西

export default defineComponent({
  setup() {
    const main = useMainStore()
    // Actions 像 methods 一样被调用:
    main.randomizeCounter()

    return {}
  },
})
//调用 Action 时,一切都会自动推断

4.访问其他 store操作

要使用另一个 store ,可以直接在操作内部使用它

import { useAuthStore } from './auth-store'

export const useSettingsStore = defineStore('settings', {
  state: () => ({
    // ...
  }),
  actions: {
    async fetchUserPreferences(preferences) {
      const auth = useAuthStore()
      if (auth.isAuthenticated) {
        this.preferences = await fetchPreferences()
      } else {
        throw new Error('User must be authenticated')
      }
    },
  },
})

5.与 setup( )一起使用

您可以直接调用任何操作作为 store 的方法

export default {
  setup() {
    const store = useStore()

    store.randomizeCounter()
  },
}

6.使用选项API

import { defineStore } from 'pinia',

const useCounterStore = defineStore('counterStore', {
  state: () => ({
    counter: 0
  }),
  actions: {
    increment() {
      this.counter++
    }
  }
})

使用setup()

import { useCounterStore } from '../stores/counterStore'

export default {
  setup() {
    const counterStore = useCounterStore()

    return { counterStore }
  },
  methods: {
    incrementAndPrint() {
      counterStore.increment()
      console.log('New Count:', counterStore.count)
    },
  },
}

不使用 setup()

import { mapActions } from 'pinia'
import { useCounterStore } from '../stores/counterStore'

export default {
  methods: {
    // gives access to this.increment() inside the component
    // same as calling from store.increment()
    ...mapActions(useCounterStore, ['increment'])
    // same as above but registers it as this.myOwnName()
    ...mapActions(useCounterStore, { myOwnName: 'doubleCounter' }),
  },
}

7.订阅 Actions

可以使用 store.$onAction() 订阅 action 及其结果。 传递给它的回调在 action 之前执行。 after 处理 Promise 并允许您在 action 完成后执行函数。

const unsubscribe = someStore.$onAction(
  ({
    name, // action 的名字
    store, // store 实例
    args, // 调用这个 action 的参数
    after, // 在这个 action 执行完毕之后,执行这个函数
    onError, // 在这个 action 抛出异常的时候,执行这个函数
  }) => {
    // 记录开始的时间变量
    const startTime = Date.now()
    // 这将在 `store` 上的操作执行之前触发
    console.log(`Start "${name}" with params [${args.join(', ')}].`)

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

    // 如果 action 抛出或返回 Promise.reject ,onError 将触发
    onError((error) => {
      console.warn(
        `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
      )
    })
  }
)

// 手动移除订阅
unsubscribe()

action subscriptions 绑定到添加它们的组件(如果 store 位于组件的 setup() 内)。当组件被卸载时,它们将被自动删除。 如果要在卸载组件后保留它们,将 true 作为第二个参数传递给当前组件的 detach action subscription

export default {
  setup() {
    const someStore = useSomeStore()

    // 此订阅将在组件卸载后保留
    someStore.$onAction(callback, true)

    // ...
  },
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值