今回やりたかったこと
学習目的の個人開発にてタイマーアプリを作成しておりまして、その設定ファイルをリアルタイムで反映させるために躓いた点と解消した方法をまとめました。
躓いた点
Svelteにstoreというreactいうところのstate的なものがあります。通常のSveltekitではstoreはグローバルで管理されるもの思っておりました。
イメージとしては、以下のに各ウィンドウからできるものかと思っていました。
しかし、実際には各ウィンドウごとにstoreが生成されるという挙動でした。そのため、設定変更がメインウィンドウへ反映されませんでした。
解決方法
元々アプリ起動時に、設定ファイルから設定情報を読み取る実装でした。設定変更時に設定ファイルへの書き込み&Mainウィンドウの設定読み込みイベントを発火することで解決できました。最終的な処理イメージは以下のようになります。
まず、③④を行うためのイベントをメインで使用する画面に実装します。
<script lang="ts">
import settingsStore, { loadSettings } from '$lib/Settings';
import { listen } from '@tauri-apps/api/event';
onMount(() => {
// イベント設定
listen('settings-changed', async (event) => {
// 設定読み込み、store更新
$settingsStore = await loadSettings();
});
});
</script>
// Settings.ts
import { readTextFile, writeTextFile, BaseDirectory } from '@tauri-apps/api/fs';
export async function loadSettings() {
try {
const config = await readTextFile(FILENAME, { dir: BaseDirectory.AppConfig });
return JSON.parse(config);
} catch (error) {
return defaultSettings;
}
}
設定画面で①②を実装します。スタイリングはdaisyUIを使ってます。
<script lang="ts">
import settingsStore from '$lib/Settings';
import { emit } from '@tauri-apps/api/event';
let timeDuration = $settingsStore.timeDuration;
async function save() {
$settingsStore.timeDuration = timeDuration;
emit('settings-changed', { $settingsStore });
}
</script>
<main>
<div class="p-4 space-y-3">
Time Duration (minutes)
<label class="input input-bordered flex items-center gap-4">
<input type="text" class="grow" bind:value={timeDuration} />
</label>
</div>
<!-- fotter -->
<div class="p-4 flex justify-end space-x-2">
<button class="btn btn-primary" on:click={save}>Save</button>
</div>
</main>
まとめ
これが正しい設計かは分かりませんが、なんとか綺麗にまとまったと思います。ちなみに作成中のタイマーアプリはこちらで紹介してます。現在も激遅アップデートを行っています。