3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Vue.jsコンポーネント管理 - watchやPiniaの$subscribeでハマったこと

Posted at

概要

まだまだVue.jsの理解も浅い中で、コンポーネント分割していたらロジックが複雑になってしまい、状態管理にPiniaを使うことにしました。
$subscribeによるState監視で意図しない動きをしてしまっていたので、メモです。そもそもこのようなPiniaの使い方がよくない可能性がありますが、、、

状況

Piniaで2つのStore(StoreA, StoreB)を利用しており、StoreAにはオブジェクト情報、StoreBにはオブジェクトのリスト情報を保持していました。
状況によって、StoreAの中にStoreBのリスト内のオブジェクトを保持するケースがありました。

storea.ts
import { defineStore } from 'pinia'

export const useStoreA = defineStore({
  id: 'storea',
  state: () => ({
    obj: {}
  }),
  getters: {
    // ...省略
  },
  actions: {
    updateObj(obj) {
      this.obj = obj
    },
    // ...省略
  }
})
storeb.ts
import { defineStore } from 'pinia'

export const useStoreB = defineStore({
  id: 'storeb',
  state: () => ({
    Array: []
  }),
  getters: {
    getObjById: (state) => (id: string) => {
        return state.obj.find((obj) => obj.id == id)
    }
  },
  actions: {
    // ...省略
  }
})

起きたこと

storeBから取得したオブジェクトをそのままstoreAに更新かけました。

const storeA = useStoreA()
const storeB = useStoreB()

const obj = storeB.getById(3)
storeA.updateObj(obj)

別のところで$subscribeを設定し、storeBのstateを監視していました。
すると、storeAのstateが更新された際に、storeBの$subscribeアクションが動いてしまいました。

解決策

getしてきたstoreBの参照を渡してしまっていることが原因だと思います。
このまま渡すのであれば、オブジェクトのディープコピーを渡すことで正しく動きました。
ディープコピーはObject.assign(), JSON.parse(), JSON.stringfy()を組み合わせて作成します。

const storeA = useStoreA()
const storeB = useStoreB()

const obj = storeB.getById(3)
storeA.updateObj(Object.assign({}, JSON.parse(JSON.stringify(obj))))
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?