🏠 ホーム
フロントエンド
PHP
Go言語
プログラミングの理解
プログラマーへの道
Google API

Go × Vue3 混在プロジェクト②

  プログラミング >     フロントエンド >  

1. 問題の発端

今回発生したエラーは以下でした。

Uncaught TypeError: Cannot read properties of undefined (reading '_s')

この _sPinia が内部で保持している store の Map であり、このエラーは

「アクティブな Pinia が存在しない状態で store を使おうとした」

ことを意味します。


2. なぜ「import しているのに」動かなかったのか

当初のコードでは以下のような構造になっていました。

この構造だけを見ると、

「必要なものはすべて import されている」

ように見えます。しかし、Pinia(および Vue の多くの仕組み)は import だけでは動作しません


3. Pinia の本質的な仕組み

Pinia は単なる関数ライブラリではなく、実行時に有効なコンテキスト(activePinia)を必要とする状態管理ライブラリです。

Pinia を使うためには、必ず次の手順が必要になります。

const pinia = createPinia()
app.use(pinia)

この処理によって初めて、

という状態になります。

useBookmarksStore()useMessagesStore() は、

「今アクティブな Pinia はどれか?」

を内部的に参照するため、activePinia が存在しないと即座にエラーになります。


4. 今回の決定的な原因

今回の outsideApp.js では、

createApp(Drawer).mount('#drawer_column')

は行われていましたが、

createPinia()
app.use(pinia)

が一切行われていませんでした。

そのため、

という流れが発生していました。


5. なぜ「Vue の外」から呼ぶと問題が顕在化するのか

Vue コンポーネントの setup() 内で store を使う場合、

app.use(pinia)

が済んでいれば、自動的に activePinia が設定されます。

しかし今回の pushReceive は、

といった Vue のライフサイクル外 から呼ばれていました。

この場合、Pinia は「どのアプリの Pinia を使えばよいか」を判断できないため、明示的に指定する必要があります


6. 解決策の本質

解決策は以下の 2 点に集約されます。

① Pinia を必ず生成し、Vue アプリに注入する

const pinia = createPinia()
app.use(pinia)

② Vue 外から store を使う入口で activePinia を設定する

import { setActivePinia } from 'pinia'

window.pushReceive = (data, fromPush = false) => {
  setActivePinia(pinia)
  return pushReceive(data, fromPush)
}

この構成により、

の両方から、同一の Pinia store を安全に利用できるようになります。


7. Pinia 以外にも同様の制約を持つ機能

今回の問題は Pinia に限りません。Vue には「実行時コンテキスト必須」の機能が多数あります。

Vue 外では動かない代表例

これらはすべて、

Vue アプリまたは plugin コンテキスト内でのみ有効

という共通点を持っています。


8. Vue 外でも安全に使えるもの

一方で、以下は Vue と無関係なため問題ありません。

今回の push 処理が IndexedDB + Pinia 更新 という構成なのは、設計として非常に正しいと言えます。


9. 設計上の重要な原則

今回の一連のトラブルから得られる最重要原則はこれです。

Vue 外では「状態の更新」だけを行い、
UI の反映は Vue に任せる

つまり、

pushReceive(Vue外)
  ↓
Pinia store を更新
  ↓
Vue コンポーネントが自動的に再描画

という流れが理想形です。


10. 総括

登録日:

更新日:

by

コメント         tweetでコメント