Alpine.jsでは x-data="{open: false}"
というように x-data
属性を付与することで、その要素の内側で x-show="open"
のように参照することができます。
<div x-data="{open: false}">
<button @click="open = !open">開閉するよ</button>
<div x-show="open">
開いてるね
</div>
</div>
とまあこれはAlpine.jsを知っている人なら全員知ってることなんですが、 x-data
でなくても $store
で同じようなことができます。
例えばこんな感じですね
<button x-data @click="$store.menu.open = !$store.menu.open">開閉するよ</button>
<div x-data x-show="$store.menu.open">
開いてるね
</div>
<script>
document.addEventListener('alpine:init', () => {
Alpine.store('menu', {
open: false,
})
})
</script>
コードでみると結構違いますが、やってることは一緒で、openという変数の定義場所が違うだけなんですよね。
$store
はコンポーネントを跨いで参照することができます。便利。
ただし、v3から x-data
は入れ子になっていても変数名がカブらない限り祖先の変数も参照できるという仕様なので、
<body x-data="{open: false}">
...
<button @click="open = !open">開閉するよ</button>
...
<div x-show="open">
開いてるね
</div>
...
</body>
このように <body>
で x-data
しちゃえばどこからでも参照できるグローバル変数を定義できちゃうんですよね。これでは$storeの立場がありません。
じゃあ $store
っていつ使うの?って話なんですが、おそらく主に下記2点に注目すべきポイントがあります
外部のJSと連携したい!
UI系のライブラリを利用する場合など、Alpine.js外のJSとステートの共有をしたい場合は往々にしてあると思います。
そんな場合には x-data
や Alpine.data
で頑張るより素直にstoreを使ったほうが良いでしょう。
<script>
Alpine.store('menu').open = true;
</script>
パフォーマンスへの影響
x-data
を付与すると Alpine.start()
を実行したときに、その要素以下がコンポーネントとして初期化されます。
もしその要素が巨大なツリーだった場合、初期化にかかるコストが大きいものになるため、できる限りコンポーネントは小さくするのがベター。
ちょっとした状態管理のためだけにbodyで x-data
をしてしまうのはコストに見合わないので、$storeを使うのがよいでしょう。