💣
SvelteでReduxを使う
ちょっとだけ経由を説明しておくと
sveltekitでフルに活用し、プロダクトを開発していて、サーバ側のテストはjestでそのままできるが、クライアントのユニットテストがjestをいれるだけでできなくて、ESM対応をいろいろしないといけない、ロジックの部分を細かい関数に切り出して、テストすればいいが、それはそれでちょっとだけコード負いづらいし、stateの変化もテストしたいという気持ちもあったのが、ことの発端
詳細が知りたい方はスクラップに雑にまとめているので、ぜひ👇
自分なりに考えてみたreduxにすることで得られメリット
- 今後別のフレームワークに移行したくなったときにもやりやすい
- v4 -> v5にアップデート時にも影響受けにくい
- 補修性が良くなる
自分なりに考えてみたデメリット
- 記述量が多い
- svelteで動かすには色々と書かないといけない
実際のざっくりしたコード貼っておくと👇のような感じ
Store.redux.ts
import { configureStore, createSlice } from '@reduxjs/toolkit';
export interface MenuFormStore {
name: string;
}
const initialState: MenuFormStore = {
name: '',
};
const menuFormSlice = createSlice({
name: 'menuForm',
initialState,
reducers: {
setName: (state, action: { payload: string }) => {
state.name = action.payload;
}
}
});
const MenuFormActions = menuFormSlice.actions;
const menuFormStoreRedux = configureStore({
reducer: menuFormSlice.reducer
});
const MenuFormDispatch = menuFormStoreRedux.dispatch;
export const MenuFormReduxStoreModule = {
initialState,
Actions: MenuFormActions,
Store: menuFormStoreRedux,
Dispatch: MenuFormDispatch
} as const;
このファイルはsvelte関係ないので、そのままjestでユニットテストが書ける。
ただ、これだけではsvelte上でreactiveにならないので、👇のようにsvelte/store
からderived
を使い読み込み専用のストアを別ファイルで定義する(同じファイルにすると、jestに怒られる)
Store.ts
import { onMount } from 'svelte';
import { writable, derived } from 'svelte/store';
import { MenuFormReduxStoreModule } from './MenuForm.redux';
const state = writable(MenuFormReduxStoreModule.initialState);
export const getMenuFormStore = () => {
onMount(() =>
MenuFormReduxStoreModule.Store.subscribe(() => {
state.update(prev => ({ ...prev, ...MenuFormReduxStoreModule.Store.getState() }));
})
);
return derived(state, $state => $state);
};
svelte内で使うと👇
Menu.svelte
<script lang="ts">
import { getMenuFormStore } from './Store';
import { MenuFormReduxStoreModule } from './Store.redux';
$: menuFormStore = getMenuFormStore();
const { Actions, DIspatch } = MenuFormReduxStoreModule;
</script>
<div>
{$menuFormStore.name}
<input on:input={e => DIspatch(Actions.setName(e.currentTarget.value))}/>
</div>
最後
恐らく同じ仕組みで、jotaiやzustandもできるはず、ここらへんはsvelte v5でいろいろ解消されているので、ありがたい。
Discussion