>  기사  >  웹 프론트엔드  >  Vue의 새로운 상태 관리 Pinia를 시작하는 방법은 이 기사를 읽어보세요!

Vue의 새로운 상태 관리 Pinia를 시작하는 방법은 이 기사를 읽어보세요!

青灯夜游
青灯夜游앞으로
2022-03-18 11:14:312314검색

Pinia는 Vue에서 개발한 새로운 상태 관리 라이브러리인데, 초보자가 Pinia를 시작하려면 어떻게 해야 하나요? 다음 글에서는 Pinia를 소개하고 핵심 기능과 간단한 사용법을 소개하겠습니다.

Vue의 새로운 상태 관리 Pinia를 시작하는 방법은 이 기사를 읽어보세요!

Vuex는 모두에게 친숙한 오래된 Vue 상태 관리 라이브러리입니다.

Pinia는 Vue.js 팀 구성원이 Vue용으로 특별히 개발한 새로운 상태 관리 라이브러리이며 공식 github에 포함되었습니다.

Vuex가 이미 있는데 왜 Pinia를 개발해야 하나요?

차세대 Vuex5가 어떤 모습이어야 할지 Vuex5에 대한 제안을 먼저 사진으로 살펴보겠습니다. [관련 추천 : vuejs 영상 튜토리얼]

Vue의 새로운 상태 관리 Pinia를 시작하는 방법은 이 기사를 읽어보세요!

Pinia는 당시 Vuex5 제안에서 언급한 기능적 사항을 완벽하게 준수하고 있어서 Pinia가 공식 개발자이기 때문에 Vuex5라고 해도 과언이 아닙니다. , 공식적으로 인수되었지만 현재 Vuex와 Pinia는 여전히 두 개의 독립적인 웨어하우스입니다. 향후 독립적으로 병합되거나 개발될 수 있지만 Vue3에서 Vuex를 사용해야 하기 때문에 공식적인 권장 사항은 Pinia

입니다. 과도기적 선택으로 사용되었으며 큰 결함이 있습니다. 따라서 Componsition API가 탄생한 후 새로운 상태 관리 Pinia

Pinia 및 Vuex

Vuex가 설계되었습니다: State, Gettes, Mutations(동기), Actions(비동기)StateGettesMutations(同步)、Actions(异步)

PiniaStateGettesActions(同步异步都支持)

Vuex 当前最新版是 4.x

  • Vuex4 用于 Vue3
  • Vuex3 用于 Vue2

Pinia 当前最新版是 2.x

  • 即支持 Vue2 也支持 Vue3

就目前而言 Pinia 比 Vuex 好太多了,解决了 Vuex 的很多问题,所以笔者也非常建议直接使用 Pinia,尤其是 TypeScript 的项目

Pinia 核心特性

  • Pinia 没有 Mutations
  • Actions 支持同步和异步
  • 没有模块的嵌套结构
    • Pinia 通过设计提供扁平结构,就是说每个 store 都是互相独立的,谁也不属于谁,也就是扁平化了,更好的代码分割且没有命名空间。当然你也可以通过在一个模块中导入另一个模块来隐式嵌套 store,甚至可以拥有 store 的循环依赖关系
  • 更好的 TypeScript 支持
    • 不需要再创建自定义的复杂包装器来支持 TypeScript 所有内容都类型化,并且 API 的设计方式也尽可能的使用 TS 类型推断
  • 不需要注入、导入函数、调用它们,享受自动补全,让我们开发更加方便
  • 无需手动添加 store,它的模块默认情况下创建就自动注册的
  • Vue2 和 Vue3 都支持
    • 除了初始化安装和SSR配置之外,两者使用上的API都是相同的
  • 支持 Vue DevTools
    • 跟踪 actions, mutations 的时间线
    • 在使用了模块的组件中就可以观察到模块本身
    • 支持 time-travel 更容易调试
    • 在 Vue2 中 Pinia 会使用 Vuex 的所有接口,所以它俩不能一起使用
    • 但是针对 Vue3 的调试工具支持还不够完美,比如还没有 time-travel 功能
  • 模块热更新
    • 无需重新加载页面就可以修改模块
    • 热更新的时候会保持任何现有状态
  • 支持使用插件扩展 Pinia 功能
  • 支持服务端渲染

Pinia 使用

Vue3 + TypeScript 为例

安装

npm install pinia

main.ts 初始化配置

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

在 store 目录下创建一个 user.ts 为例,我们先定义并导出一个名为 user 的模块

import { defineStore } from 'pinia'
export const userStore = defineStore('user', {
    state: () => {
        return { 
            count: 1,
            arr: []
        }
    },
    getters: { ... },
    actions: { ... }
})

defineStore

Pinia
: State, Gettes code>, Actions (동기식 및 비동기식 모두 지원)

🎜Vuex 최신 버전은 4.x🎜
  • Vue3에는 Vuex4가 사용됩니다. /li>
  • Vuex3은 Vue2에 사용됩니다.
🎜Pinia 최신 버전은 2.x🎜
  • Vue2와 Vue3을 모두 지원합니다
li>🎜현재 Pinia는 Vuex보다 훨씬 뛰어나고 Vuex의 많은 문제를 해결하므로 특히 TypeScript 프로젝트의 경우 Pinia를 직접 사용하는 것이 좋습니다🎜

Pinia 핵심 기능🎜
  • Pinia에는 돌연변이가 없습니다
  • Actions는 동기식 및 비동기식을 지원합니다
  • 모듈의 중첩 구조 없음
    • 피니아는 디자인을 통해 플랫한 구조를 제공합니다. 즉, 각 매장은 서로 독립적이고 어느 누구도 누구에게도 속하지 않으며 코드 분리가 더 잘되고 네임스페이스가 없습니다. . 물론 한 모듈에서 다른 모듈을 가져와 암시적으로 저장소를 중첩할 수도 있고 저장소의 순환 종속성을 가질 수도 있습니다.
  • 더 나은 TypeScript 지원
    • TypeScript를 지원하기 위해 사용자 정의 복잡한 래퍼를 만들 필요가 없으며 API는 가능한 한 TS 유형 추론을 사용하도록 설계되었습니다.
  • 삽입, 함수 가져오기, 호출, 자동 완성을 즐길 필요가 없으므로 개발이 더욱 편리해집니다.
  • 수동으로 스토어를 추가할 필요가 없으며 해당 모듈은 생성 시 기본적으로 자동으로 등록됩니다.
  • 수동으로 스토어를 추가할 필요가 없습니다. li>
  • Vue2와 Vue3 모두 지원
    • 초기 설치 및 SSR 구성을 제외하고 둘 다 사용하는 API는 동일합니다.
  • Vue DevTools
    • 액션 및 변이의 타임라인 추적
    • 모듈 자체를 해당 모듈을 사용하는 구성 요소에서 관찰할 수 있습니다.
    • 시간 지원- 여행은 디버깅을 더 쉽게 만듭니다.
    • Vue2에서 Pinia는 Vuex의 모든 인터페이스를 사용하므로 함께 사용할 수 없습니다.
    • 그러나 Vue3에 대한 디버깅 도구 지원은 충분하지 않습니다. 완벽합니다. 예를 들어, 시간 이동 기능이 없습니다
  • 모듈 핫 업데이트
    • 페이지를 다시 로드하지 않고도 모듈을 수정할 수 있습니다.
    • 핫 업데이트 기존 상태는 유지됩니다
  • Pinia 기능 확장을 위한 플러그인 사용 지원
  • 서버 측 렌더링 지원

Pinia는 🎜🎜Vue3 + TypeScript를 예로 사용합니다🎜🎜installation🎜
<template>
    <div>{{ user_store.count }}</div>
</template>
<script setup>
import { userStore } from &#39;../store&#39;
const user_store = userStore()
// 解构
// const { count } = userStore()
</script>
🎜main.ts 초기화 구성🎜
<template>
    <div>{{ count }}</div>
</template>
<script setup>
import { storeToRefs } from &#39;pinia&#39;
import { userStore } from &#39;../store&#39;
const { count } = storeToRefs(userStore)
</script>
🎜in store 디렉토리에 user.ts를 생성합니다. 예를 들어 먼저 user라는 모듈을 정의하고 내보냅니다. 🎜
<template>
    <div>{{ myCount }}</div>
    <div>{{ myCount }}</div>
    <div>{{ myCount }}</div>
</template>
🎜defineStore는 수신합니다. 두 개의 매개변수 🎜🎜첫 번째 매개변수는 모듈의 이름이며, 여러 모듈이 동일한 이름을 가질 수 없습니다. Pinia는 모든 모듈을 루트 컨테이너에 마운트합니다. Vuex Almost🎜와 동일
  • 其中 state 用来存储全局状态,它必须是箭头函数,为了在服务端渲染的时候避免交叉请求导致的数据状态污染所以只能是函数,而必须用箭头函数则为了更好的 TS 类型推导
  • getters 就是用来封装计算属性,它有缓存的功能
  • actions 就是用来封装业务逻辑,修改 state

访问 state

比如我们要在页面中访问 state 里的属性 count

由于 defineStore 会返回一个函数,所以要先调用拿到数据对象,然后就可以在模板中直接使用了

<template>
    <div>{{ user_store.count }}</div>
</template>
<script setup>
import { userStore } from &#39;../store&#39;
const user_store = userStore()
// 解构
// const { count } = userStore()
</script>

比如像注释中的解构出来使用,是完全没有问题的,只是注意了,这样拿到的数据不是响应式的,如果要解构还保持响应式就要用到一个方法 storeToRefs(),示例如下

<template>
    <div>{{ count }}</div>
</template>
<script setup>
import { storeToRefs } from &#39;pinia&#39;
import { userStore } from &#39;../store&#39;
const { count } = storeToRefs(userStore)
</script>

原因就是 Pinia 其实是把 state 数据都做了 reactive 处理,和 Vue3 的 reactive 同理,解构出来的也不是响应式,所以需要再做 ref 响应式代理

getters

这个和 Vuex 的 getters 一样,也有缓存功能。如下在页面中多次使用,第一次会调用 getters,数据没有改变的情况下之后会读取缓存

<template>
    <div>{{ myCount }}</div>
    <div>{{ myCount }}</div>
    <div>{{ myCount }}</div>
</template>

注意两种方法的区别,写在注释里了

getters: {
    // 方法一,接收一个可选参数 state
    myCount(state){
        console.log(&#39;调用了&#39;) // 页面中使用了三次,这里只会执行一次,然后缓存起来了
        return state.count + 1
    },
    // 方法二,不传参数,使用 this
    // 但是必须指定函数返回值的类型,否则类型推导不出来
    myCount(): number{
        return this.count + 1
    }
}

更新和 actions

更新 state 里的数据有四种方法,我们先看三种简单的更新,说明都写在注释里了

<template>
    <div>{{ user_store.count }}</div>
    <button @click="handleClick">按钮</button>
</template>
<script setup>
import { userStore } from &#39;../store&#39;
const user_store = userStore()
const handleClick = () => {
    // 方法一
    user_store.count++
    
    // 方法二,需要修改多个数据,建议用 $patch 批量更新,传入一个对象
    user_store.$patch({
        count: user_store.count1++,
        // arr: user_store.arr.push(1) // 错误
        arr: [ ...user_store.arr, 1 ] // 可以,但是还得把整个数组都拿出来解构,就没必要
    })
    
    // 使用 $patch 性能更优,因为多个数据更新只会更新一次视图
    
    // 方法三,还是$patch,传入函数,第一个参数就是 state
    user_store.$patch( state => {
        state.count++
        state.arr.push(1)
    })
}
</script>

第四种方法就是当逻辑比较多或者请求的时候,我们就可以封装到示例中 store/user.ts 里的 actions 里

可以传参数,也可以通过 this.xx 可以直接获取到 state 里的数据,需要注意的是不能用箭头函数定义 actions,不然就会绑定外部的 this 了

actions: {
    changeState(num: number){ // 不能用箭头函数
        this.count += num
    }
}

调用

const handleClick = () => {
    user_store.changeState(1)
}

支持 VueDevtools

打开开发者工具的 Vue Devtools 就会发现 Pinia,而且可以手动修改数据调试,非常方便

Vue의 새로운 상태 관리 Pinia를 시작하는 방법은 이 기사를 읽어보세요!

模拟调用接口

示例:

我们先定义示例接口 api/user.ts

// 接口数据类型
export interface userListType{
    id: number
    name: string
    age: number
}
// 模拟请求接口返回的数据
const userList = [
    { id: 1, name: &#39;张三&#39;, age: 18 },
    { id: 2, name: &#39;李四&#39;, age: 19 },
]
// 封装模拟异步效果的定时器
async function wait(delay: number){
    return new Promise((resolve) => setTimeout(resolve, delay))
}
// 接口
export const getUserList = async () => {
    await wait(100) // 延迟100毫秒返回
    return userList
}

然后在 store/user.ts 里的 actions 封装调用接口

import { defineStore } from &#39;pinia&#39;
import { getUserList, userListType } from &#39;../api/user&#39;
export const userStore = defineStore(&#39;user&#39;, {
    state: () => {
        return {
            // 用户列表
            list: [] as userListType // 类型转换成 userListType
        }
    },
    actions: { 
        async loadUserList(){
            const list = await getUserList()
            this.list = list
        }
    }
})

页面中调用 actions 发起请求

<template>
    <ul>
        <li v-for="item in user_store.list"> ... </li>
    </ul>
</template>
<script setup>
import { userStore } from &#39;../store&#39;
const user_store = userStore()
user_store.loadUserList() // 加载所有数据
</script>

跨模块修改数据

在一个模块的 actions 里需要修改另一个模块的 state 数据

示例:比如在 chat 模块里修改 user 模块里某个用户的名称

// chat.ts
import { defineStore } from &#39;pinia&#39;
import { userStore } from &#39;./user&#39;
export const chatStore = defineStore(&#39;chat&#39;, {
    actions: { 
        someMethod(userItem){
            userItem.name = &#39;新的名字&#39;
            const user_store = userStore()
            user_store.updateUserName(userItem)
        }
    }
})

user 模块里

// user.ts
import { defineStore } from &#39;pinia&#39;
export const userStore = defineStore(&#39;user&#39;, {
    state: () => {
        return {
            list: []
        }
    },
    actions: { 
        updateUserName(userItem){
            const user = this.list.find(item => item.id === userItem.id)
            if(user){
                user.name = userItem.name
            }
        }
    }
})

(学习视频分享:vuejs教程web前端

위 내용은 Vue의 새로운 상태 관리 Pinia를 시작하는 방법은 이 기사를 읽어보세요!의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제