DEV Community

Cover image for use Redux with Svelte ๐Ÿ‘€
qaynam
qaynam

Posted on • Updated on

use Redux with Svelte ๐Ÿ‘€

I've been developing a product fully utilizing SvelteKit, and while server-side tests can be handled directly with Jest, unit testing on the client side can't be done just by adding Jest. Support for ESM needs to be added in various ways, it would be fine to break down logic into smaller functions for testing, but that makes the code a bit cumbersome to manage, and I also wanted to test changes in state, which was the start of it all.

Benefits I've considered by deciding on Redux:

  • Makes it easier to transition to a different framework in the future
    • Less affected when updating from v4 to v5
  • Improves maintainability

Disadvantages I've considered:

  • Increases the amount of code
  • Requires various adjustments to operate in Svelte

Here is a rough code snippet like below๐Ÿ‘‡

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;

Enter fullscreen mode Exit fullscreen mode

This file has nothing to do with Svelte, so you can write unit tests directly with Jest.
However, this alone does not make it reactive on Svelte, so we define a read-only store in a separate file using readonly from svelte/store like below (placing it in the same file will anger Jest)

Store.ts

import { onMount } from 'svelte';
import { writable, readonly } 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 readonly(state);
};

Enter fullscreen mode Exit fullscreen mode

Usage within Svelte would be as below๐Ÿ‘‡

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>

Enter fullscreen mode Exit fullscreen mode

In Conclusion

Likely the same system could be used for jotai or zustand, which is appreciated since many issues are resolved in Svelte v5.

Top comments (0)