ReduxまたはVuexに精通している場合、Svelteストアは状態管理のための同様の機能を提供します。 アプリが複雑になると、コンポーネント間でデータを中継することが難しくなります。 グローバルデータストアに移動することをお勧めします。 ここでは、Svelteが提供する2つのストアオプション、書き込み可能ストア読み取り可能ストアについて説明します。

書き込み可能なストア

先に進んで、Svelteプロジェクトにグローバル状態管理ファイルを作成しましょう。それをstore.jsと呼び、writable関数をインポートしましょう。

import { writable } from "svelte/store";

let counter = writable(1);

export {counter}

書き込み可能なストアであるcounterという変数を作成しました。 counterには、次の自明のメソッドがあります。

  • set
  • update

Nested.svelteというカスタムコンポーネントを作成し、作成したcounterストアを使用してみましょう。

<script>
import { counter } from "./store.js";
</script>

<div>
 counter value: {$counter}
</div>

これは名前付きインポートであるため、使用中は変数の前に$を付けることに注意してください。

コンポーネントをApp.svelteファイルにインポートしてまとめ、counter変数を記述して、ネストされたコンポーネント間の反応性を観察するメソッドを作成しましょう。

<script>
import Nested from "./Nested.svelte";
import { counter } from "./store.js";

function incrementCounter() {
  counter.update(n => n + 1);
}
</script>

<div>
<button on:click={incrementCounter}>Update</button>
<Nested />
</div>

counterは、updateメソッドを使用します。このメソッドは、パラメーターが書き込み可能ストアの現在の値であり、変更された値を返す関数を取ります。 このアプリを実行すると、ボタンをクリックすると、Nestedコンポーネント内の値が更新されるのを確認できるはずです。

その間に、resetボタンをApp.svelteに追加してみましょう。

function resetCounter() {
  counter.set(1);
}
<button on:click={resetCounter}>Reset</button>

resetCounterは、書き込み可能なストアのsetメソッドを使用します。

現在、writable関数は、これも関数である2番目の引数もサポートしています。 その関数のシグネチャは次のとおりです。

writable(value: any, (set: (value: any) => void) => () => void)

この関数は、最初のサブスクライバーが作成されたときに起動され、変数への最後のサブスクリプションが破棄されたときに起動される別の関数を返します。 それが実際に動いているのを見てみましょう。

store.jsで、書き込み可能な関数に2番目の引数を追加します。

let counter = writable(1, () => {
  console.log("First subscriber added!");
  return () => {
    console.log("Last subscriber deleted :(");
  };
});

これをテストするために、Nestedコンポーネントをマウントおよびアンマウントして、App.svelteで動作を観察します。

<script>
// ...
let flag = false;
function toggleMount() {
    flag = !flag;
}
</script>

  <!-- ... -->

  <button on:click={toggleMount}>Mount/Unmount</button>

  {#if flag}
    <Nested />
  {/if}
</div>

読みやすい店

Svelteはreadable関数も提供します。これにより、他のコンポーネントから値を更新できない読み取り可能なストアを作成できます。 値はストア内からsetにする必要があります。 これを試して、store.jsを変更してみましょう-

import { readable } from "svelte/store";

let initialVal = Math.floor(Math.random()*100);

let counter = readable(initialVal, (set) => {
  let incrementCounter = setInterval( () => {
    let newVal = Math.floor(Math.random()*100);
    set(newVal);
  }, 1000);
  return () => {
    clearInterval(incrementCounter);
  };
});

export {counter}

ここで、readableカウンターは、最初の引数として渡されるinitialValで設定されます。 2番目の引数は書き込み可能なストアの場合と同じですが、これがないとcounter値にアクセスしてリセットする方法が他にないため、今回は必須パラメーターです。

この例では、0〜100の乱数を生成し、setメソッドを使用してこれをcounterに割り当てます。 updateは使用できません。 これは単純なデモですが、実際のアプリでは、読み取り可能なストアは2番目の引数を使用してAPI呼び出しを行い、一部のロジックに基づいてset値を指定できます。 これにより、このストアにサブスクライブされているコンポーネントがレンダリングされます。


ご覧のとおり、Svelteのwritableストアとreadableストアを使用することで、基本的な形式のグローバル状態管理を非常に簡単に実現できます。 ✨