Pinia Study Notes | Getting Started - Mapping Helper Functions

Pinia Study Notes

Reference article 1: Get started with Vue’s new state management Pinia, one article is enough
Reference article 2:
Author: Nanshan Seed Delivery Runner
Link: https://juejin.cn/post/7089032094231298084
Source: Rare Earth Nuggets
Copyright belongs to the author all. For commercial reprint, please contact the author for authorization, for non-commercial reprint, please indicate the source.

Introduction

There is a problem: the data cannot be persisted

What is Pinia?

Pinia is a brand-new Vue state management library, a replacement for Vuex (it can be understood as Vuex5, Vuex will not be updated), and can realize communication between any components.

Pinia and Vuex

Vuex Pineapple
state, getters, mutations(synchronous), actions(asynchronous),modules state, getters, actions(both synchronous and asynchronous are supported)
Vuex4 for Vue3, Vuex3 for Vue2 Both Vue2 and Vue3 support

Other features of Pinia

  • Provide a flat structure, each store is independent of each other. So pinia has better code segmentation and no namespace, and you can also implicitly nest stores by importing another module in one module.
  • Both Vue2 and Vue3 support, except for initial installation and SSR configuration, the APIs used by both are the same
  • supportVue DevTools
  • Module hot update
    • Modules can be modified without reloading the page
    • Any existing state will be maintained during a hot update
  • Support for extending Pinia functionality with plugins
  • Support server-side rendering

mutation has been deprecated, the original intention is to bring devtools integration solution

Code Splitting Mechanism Case

A certain project has 3 stores "user, job, pay", and 2 routing pages "home page, personal center page". The home page uses the job store, and the personal center page uses the user store. Pinia and Vuex are used to check the status respectively. manage.
insert image description here
First look at the code segmentation of Vuex: When packaging, vuex will merge and package the three stores. When Vuex is used on the homepage, this package will be introduced to the homepage and packaged together, and finally a js chunk will be output. The problem with this is that, in fact, only one store is needed for the home page, but the other two irrelevant stores are also packaged in, resulting in a waste of resources.

insert image description here

Pinia's code segmentation: When packaging, Pinia will check the reference dependencies. When the home page uses the job store, the packaging will only combine the used store and the page to output a js chunk, and the other two stores will not be coupled in it. Pinia can do this because its design is that the store is separated, which solves the coupling problem of the project.

1. Mount Pinia

install pinianpm install pinia

View 3

createPinia: Create a large warehouse (root capacity), and the large warehouse can manage the small warehouse

import {
    
     createApp } from 'vue'
import {
    
     createPinia } from 'pinia'; //引入createPinia 
import App from'./App.vue' //引入根组件

const pinia = createPinia() //创建pinia实例 大仓库
const app = creatApp(App) //创建Vue应用实例

app.use(pinia)//安装pinia插件
app.mount('#app')

Vue2: install PiniaVuePluginplugin

import {
    
     createPinia,PiniaVuePlugin } from 'pinia';

Vue.use(PiniaVuePlugin)
const pinia = createPinia() //创建pinia实例
new Vue({
    
    
  router,
  store,
  render: h => h(App),
  pinia
}).$mount('#app')

2. Two ways to define store options API and composition API

defineStore()

  • The first parameter is the unique name id representing the store, and Pinia will mount all modules on the root container
  • The second parameter accepts two types of values: a Setup function or an Option object.
    • The second parameter is Option对象the writing method corresponding to the options API
      • stateA function that returns the initial state. Must be an arrow function, which is good for TS type deduction. The reason why it must be a function is to prevent data state pollution caused by cross-requests during server-side rendering (client-side rendering makes no difference)
      • getters It is used to encapsulate computed properties, similar to computed of components, with caching function
      • actionsIt is used to encapsulate business logic, similar to methods of components, to modify state
    • The second parameter is Setup函数the writing method corresponding to the composition API
      • ref()Yes stateattribute, used to store storethe data in the container
      • computed()yesgetters
      • functionYes action, modify state
  • storeThe return value is a function that returns the container instance (small warehouse) after the function is called

Pinia will hang all containers (small warehouses) on the root container (big warehouse)

Defined using the options API schema

// 创建小仓库
import {
    
     defineStore } from 'pinia';
export const useCounterStore = defineStore('counterForOptions', {
    
    
  state: () => {
    
    
    return {
    
     count: 1 };
  },
 actions:{
    
    
        changeState(){
    
     //通过this访问容器里的数据
            this.count++
        }
    }
  getters: {
    
    
  	//参数state是状态数据,可选参数
    doubleCount(state) {
    
    
      return state.count * 2;
    }
     doubleCount1(state):number {
    
     //也可以使用this,但是类型推导存在问题,必须手动指定返回值类型
      return this.count * 2;
    }
  }
});

Using the composition API pattern

import {
    
     ref, computed } from 'vue';
import {
    
     defineStore } from 'pinia';
export const useCounterStore = defineStore('counterForSetup', () => {
    
    
  const count = ref<number>(1);
  const doubleCount = computed(() => count.value * 2);
  function increment() {
    
    
    count.value++;
  }

  return {
    
     count, doubleCount, increment };
});

2. The use of store by business components

Create a store instance

Create an instance when calling defineStore()the returned function store, storethe instance is a wrapped reactiveobject

storeInstance (small warehouse) example, data is bound to the instance
insert image description here

//组件内使用
<script setup>
//useCounterStore接收defineStore返回的函数
import {
    
     useCounterStore } from '@/stores/counter'
// 可以在组件中的任意位置访问 `store` 变量 ✨
const store = useCounterStore()
</script>

When used outside the component, it must be inside the function

import {
    
     useAuthUserStore } from '@/stores/auth-user'

router.beforeEach((to, from, next) => {
    
    
	//因为路由器是在其被安装之后开始导航的
  // 必须在函数内部使用,为确保 pinia 实例被激活
  const authUserStore = useCounterStore()
  if (authUserStore.loggedIn) next()
  else next('/login')
})

Destructuring access to Pinia container data

The directly destructured count variable will lose its responsiveness and become one-time data.

//组件中的代码
<script setup lang="ts">
import {
    
    useMainStore} from '../store'
const {
    
    count} = useMainStore()
</script>

<template>
  <div>{
    
    {
    
    count }}</div>
</template>

Solution: use storeToRefs()the method, the role of this method is to use the deconstructed data as refa responsive proxy

storeToRefs()method

  • The role is to create a reference method. Contains all state, getter and plugin added state attributes of the store, and skips all action or non-responsive (not ref or reactive) attributes
  • toRefAn api method used and toRefsimplemented by the bottom layer
<script setup lang="ts">
import {
    
    useMainStore} from '../store'
import {
    
    storeToRefs} from 'pinia'
const {
    
    count} = storeToRefs(useMainStore())
/*ObjectRefImpl
{
    "_object": {
        "count": 1
    },
    "_key": "count",
    "__v_isRef": true
}
*/
console.log(count)
console.log(count.value) //1
</script>

Status Updates and Actions

store $patch(): batch update state
- parameters can be objects and functions (parameters are state)

<script setup lang="ts">
import {
    
    useMainStore} from '../store'
import {
    
    storeToRefs} from 'pinia'
const mainStore = useMainStore()
const {
    
    count} = storeToRefs(useMainStore())
const changeCount = ()=>{
    
    
  //方式1:最简单的方式
  // mainStore.count++; 
  //方式2:如果需要多个数据,建议使用$patch,批量更新
  //mainStore.$patch({
    
    
  //  count:mainStore.count+1,
    //...数据名:修改后的值
    //涉及数组很麻烦
 // })
  
  //方式3:$patch(函数)其中函数的参数是state就是store的state,批量更新
  //mainStore.$patch(state=>{
    
    
  //  state.count++
  //})

  //方法4:逻辑比较多的时候可以封装到actions做处理,
  mainStore.changeState()
}
</script>

It can also be constructed directly storefrom it action, because the action is also bound to the store

<script setup lang="ts">
import {
    
    useMainStore} from '../store'
const mainStore = useMainStore()
const {
    
    changeState} = store
</script>

getters use

//虽然使用了三次,但是只会调用一次,有缓存功能
<template>
  <div>
   <div>{
    
    {
    
    mainStore.count }}</div>
   <p>
      <button @click="changeCount">修改数据</button>
   </p>
   <p>{
    
    {
    
    mainStore.doubleCount}}</p>
   <p>{
    
    {
    
    mainStore.doubleCount}}</p>
   <p>{
    
    {
    
    mainStore.doubleCount}}</p>
  </div>
</template>

Pinia and VueDevtools

insert image description here

insert image description here

mapping helper function

  • mapStores()
  • mapState(): stateMaps the property as a read-only computed property
  • mapWritableState(): Map statethe attribute to a modifiable computed attribute, similar mapState(), the difference is that the second parameter cannot pass a function
  • mapActions()

1. No longer use mapMutations.
2. In order to be compatible with the mapping helper functions similar to the Vuex map series provided by the option api, Pinia is not recommended.
3. mapGetters = mapState, the underlying implementation logic of mapGetters is the same as mapState

mapState() : stateMap properties as read-only computed properties

  • Use arrays to map directly with the same name:…mapState(store, [‘count’])
  • Use objects mappable to new names:…mapState(store, { myOwnName: stateValue| fn (state) })
    • When using an object, valuethe value can be a string or a function;
    • Functions can also be defined directly inside the object, receiving storeas parameters

insert image description here

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

export default {
    
    
  computed: {
    
    
    // 生成的计算属性名字为count,值等于 store.count 
    ...mapState(useCounterStore, ['count'])
    // 第二个参数是对象的写法
    ...mapState(useCounterStore, {
    
    
      myOwnName: 'count',
      // 你也可以写一个函数来获得对 store 的访问权
      double: store => store.count * 2,
      // 它可以访问 `this`,但它没有标注类型...
      magicValue(store) {
    
    
        return store.someGetter + this.count + this.double
      },
    }),
  },
}

Guess you like

Origin blog.csdn.net/qq_41370833/article/details/131702779