이 글은 Vue 3의 공식 Store | Pinia 를 보고 정리한 글입니다.
더 자세한 내용을 원하시면 공식 문서를 참고하세요.
Pinia에서 상태는 초기 상태를 반환하는 함수로 정의됩니다. 이를 통해 Pinia는 Server측과 Client측 모두에서 작동할 수 있습니다.
mport { defineStore } from 'pinia'
export const useStore = defineStore('storeId', {
// 화살표 함수는 전체 유형 유추을 위해 권장됨.
state: () => {
return {
// 이 모든 속성은 자동으로 유형이 유추됨.
count: 0,
name: 'Eduardo',
isAdmin: true,
items: [],
hasChanged: true,
}
},
})
Vue 2를 사용하는 경우, state에서 생성한 데이터는 Vue의 인스턴스의 data와 동일한 규칙을 가집니다. 즉, 상태 객체는 일반 객체여야 하며, 새 속성을 추가할 때 Vue.set()을 호출해야합니다.
참조: Vue#data.
state에 접근
store 인스턴스로 상태에 접근하여 상태를 직접 읽고 쓸 수 있습니다 :
const store = useStore()
store.count++
만약 state()에 상태를 정의해두지 않았다면, 새 상태 속성을 추가하거나 수정할 수 없습니다.
상태 재설정
const store = useStore()
store.$reset()
- 현재 $reset() 함수는 Options 에서만 사용할 수 있다. ( 공식 문서 :https://pinia.vuejs.org/api/interfaces/pinia._StoreWithState.html#reset )
- setup store에서 사용하는 방식은 공식에서 제공해줄 때 까지 해당 블로그를 참고하도록 하자.
옵션 API와 사용
import { defindeStore } from 'pinia'
export const useCounterStore = defineStore('counter',{
state: () => ({
count: 0,
})
})
compostion API를 사용하지 않고 computed, methods , ... 를 사용하는 경우, mapState() 헬퍼를 사용하여 상태 속성을 읽기 전용 계산된 속성으로 mapping 할 수 있습니다. :
import { mapState } from 'pinia'
import { useCounterStore } from '../store/counter'
export default {
computed : {
// 컴포넌트 내부에서 `this.coutner`로 접근 할 수 있게 함.
// `store.count`로 읽는 것과 동일
...mapState(useCounterStore, ['counter']),
// 위와 같지만 `this.myOwnName`으로 등록
...mapState(useCounterStore,{
myOwnName: 'counter',
// store에 접근하는 함수를 작성할 수도 있음
double: store => store.count * 2,
// `this`에 접근할 수 있지만, 올바르게 입력되지 않음...
magicValue(store){
return store.someGetter + this.count + this.double
}
})
}
}
수정 가능한 상태
이러한 상태 속성을 쓸 수 있도록 하려면(ex: form 형식), mapWritableState()를 사용해야 합니다.
mapState()처럼 함수를 전달할 수 없습니다. :
import { mapWritableState } from 'pinia'
import { useCounterStore } from '../stores/counter'
export default {
computed: {
// 컴포넌트 내부에서 `this.count`로 접근할 수 있게 하고,
// `this.count++`와 같이 수정도 허용함.
// `store.count`에서 읽는 것과 동일.
...mapWritableState(useCounterStore, ['count']),
// 위와 같지만 `this.myOwnName`으로 등록.
...mapWritableState(useCounterStore, {
myOwnName: 'count',
}),
},
}
배열 전체를 cartItems = []처럼 바꾸지 않는 한, 배열 컬렉션은 mapWritableState()가 필요하지 않습니다. mapState()를 사용하면 컬렉션에서 메서드를 호출할 수 있습니다.
상태 변경하기
store.count++ 로 스토어를 직접 변경하는 방법 외에도, $patch 메소드를 호출하여 변경할 수 있습니다. 이 방법을 사용하여 state 객체의 일부분을 동시에 변경할 수 있습니다. :
store.$patch({
count: store.count + 1,
age : 120,
name : 'DIO'
})
일부 mutation은 이러한 문법으로 적용하기가 힘들거나 cost가 많이 듭니다.
컬렉션을 수정(예: 배열에서 요소를 푸시, 제거, 스플라이스)하려면, 새 컬렉션을 만들어야 합니다.
이 때문에 $patch 메소드는 패치 객체로 적용하기 어려운 이러한 종류의 mutations를 그룹화하는 함수도 허용합니다:
store.$patch((state) => {
state.items.push({ name: 'shoes', quantity: 1 })
state.hasChanged = true
})
여기서 주요 차이점은 $patch()를 사용하여 devtools에서 여러 변경 사항을 하나의 항목으로 그룹화할 수 있다는 것입니다.
state와 $patch()에 대한 직접적인 변경 사항은 모두 devtools에 나타나며, 시간 추적이 가능합니다. (아직 Vue 3에는 없음).
state 교체하기
반응성을 깨뜨릴 수 있으므로 스토어의 상태를 정확히 교체할 수 없지만 패치하여 사용할 수 있습니다.
// 실제로 `$state`를 교체하지 않음
store.$state = { count: 24 }
// 아래와 같이 내부적으로 `$patch()` 를 호출함 :
store.$patch({ count : 24 })
또한 어플리케이션의 초기상태를 설정하여 피니아 인스턴스의 state를 변경할 수 있습니다. 이것은 하이드레이션을 위한 SSR 중에 사용됩니다.
pinia.state.value = {}
Q. Pattern for updating Pinia state ?
A. https://github.com/vuejs/pinia/discussions/1264
Best practice for updating Pinia state? · Discussion #1264 · vuejs/pinia
I'm wondering if there is a best practice, or convention for updating state in Pinia. Let's say you have some state like this: export const useExampleStore = defineStore('ExampleStore&#...
github.com
Q. Can you do something like this with Pinia?
const exampleStore = useExampleStore()
const { isLoaded } = storeToRef(exampleStore)
isLoaded.value = true
Or is this a bad practice and I should use action or $patch?
A . Yes, you can.
트위터에서 즐기는 Eduardo.𝚟𝚞𝚎
“@jswriter_ @vuejs Yes, you can”
twitter.com
상태 구독하기
Vuex의 subscribe 메소드와 마찬가지로, 스토어의 $subscribe() 메소드를 통해 상태의 변경 사항을 감시할 수 있습니다.
일반 watch()보다 $subscribe() 사용시 장점은 구독이 여러 패치(예: 위에서 언급한 것처럼, $patch에 함수를 전달하고, 함수 내부에서 여러번의 패치가 실행됨) 이후에 한 번만 트리거된다는 것입니다.
cartStore.$subscribe((mutation, state) => {
// import { MutationType } from 'pinia'
mutation.type // 'direct' | 'patch object' | 'patch function'
// `cartStore.$id`와 동일.
mutation.storeId // 'cart'
// `mutation.type === 'patch object'`에서만 사용 가능.
mutation.payload // cartStore.$patch()에 전달된 패치 객체
// 변경될 때마다 전체 상태를 로컬 스토리지에 유지
localStorage.setItem('cart', JSON.stringify(state))
})
기본적으로 상태 구독은 컴포넌트에 추가된(스토어가 컴포넌트의 setup() 내부에 있는) 경우에 바인딩됩니다. 따라서 컴포넌트가 마운트 해제되면 자동으로 제거됩니다. 컴포넌트가 마운트 해제된 후에도 이를 유지하려면, 두 번째 인수로 현재 컴포넌트에서 상태 구독을 분리하는
{ detached: true }를 전달합니다:
export default {
setup() {
const someStore = useSomeStore()
// 이 구독은 컴포넌트가 마운트 해제된 후에도 유지됨.
someStore.$subscribe(callback, { detached: true })
// ...
},
}
Pinia 인스턴스에서 전체 상태를 감시할 수 있습니다.
watch(
pinia.state,
(state) => {
// 변경될 때마다 전체 상태를 로컬 스토리지에 유지
localStorage.setItem('piniaState', JSON.stringify(state))
},
{ deep: true }
)
'IT > Pinia' 카테고리의 다른 글
Vue3 ) script setup (0) | 2023.03.28 |
---|---|
Pinia - Action ( Option Store ) (0) | 2023.01.02 |
Pinia - Getter ( Option Store ) (0) | 2023.01.02 |
Pinia (0) | 2022.12.30 |