Linguine Code

How to add Redux to Svelte

Are you looking to add Redux to your Svelte application? If so, this is the article for you!

If you’re not sure what Redux is and why you should use it, than check out the first half of this article then comeback!

Let’s get into the good stuff now.

Install dependencies

The first step is to install 2 NPM modules


npm i -D redux svelte-redux-connect

The first module being installed is Redux, of course.

The second module is svelte-redux-connect. This is a neat little module that replicates react-redux.

Essentially, svelte-redux-connect is just a Svelte wrapper to integrate Redux with Svelte.

Create Redux store

In the root of src directory, I like to create a file called store.js.


import { createStore, combineReducers, applyMiddleware } from 'redux';

import catReducer from './reducers/cats';

export const createReducer = (initialState, handlers) => {
  return (state = initialState, action) => {
    return (handlers[action.type] && handlers[action.type](state, action)) || state;
  };
};

const rootReducer = combineReducers({
  cats: catReducer,
});

export default createStore(rootReducer, {});

Let’s do a code breakdown.

First, I’m importing the Redux utilities in my store.js file.

And I’m also importing a reducer file for my cats because who doesn’t like cats.


import { createStore, combineReducers, applyMiddleware } from 'redux';

import catReducer from './reducers/cats';

The next snippet of code is a function that I created, createReducer.


export const createReducer = (initialState, handlers) => {
  return (state = initialState, action) => {
    return (handlers[action.type] && handlers[action.type](state, action)) || state;
  };
};

createReducer is a custom function that creates a Redux reducer. It does this by gluing together the initial state, and the actions.

This function will be exported so any of my reducer files can use it.

The next snippet of code is a variable that uses Redux combineReducers to merge all my reducers into a single reducer.


const rootReducer = combineReducers({
  cats: catReducer,
});

Redux is all about a single source of truth.

The rest is simple. All I’m doing is exporting the created Redux store by using the createStore utility from Redux.


export default createStore(rootReducer, {});

Create a Redux reducer

In the root level of the src directory, I’m going to create another directory called, reducers.

Inside my reducers directory I’m going to create a file called cats.js.

Here’s the code the cat reducer file.


import { createReducer } from '../store';

const initialState = {
  list: [],
};

const actions = {
  'ADD_CAT': addCat,
};

function addCat(state, action) {
  return {
    list: [...state.list, action.payload],
  }
}

export default createReducer(initialState, actions);

initialState is a model of what the cat state will look like in the Redux store.

actions is a key-value variable object. The key in the object represents the action identifier that needs to be called for a dispatch().

And the value is the function reducer to update the state object for cats.

At the end of the file, I’m using the createReducer function that was created in store.js.

And I will export the cat reducer that is created by the function.

Add Redux store to Svelte application

So far I’ve installed the modules, created my store.js file, and created a reducer.

Redux works best when it’s the top component in the application.

That way any other Svelte components nested inside may receive or have access to the Redux store.

To make this happen, I’m going to add the Provider component provided by svelte-redux-connect, and inject it in the App.js file.


<script>
  import { Provider } from 'svelte-redux-connect';

  import store from './store.js';
</script>

<Provider {store}>
</Provider>

I’m also importing my store from store.js, and passing it as a property in the Provider component.

Connecting a Svelte component to Redux store

In the src directory I’m going to create 2 additional files, cat-list.svelte, and cat-list.js.

Let’s add some code to the cat-list.svelte file.


<script>
  import { onMount } from 'svelte';

  // Function to add a cat (catName: string) => void;
  export let addCat;

  // List of cats Array<{name: string}>
  export let catList

  onMount(() => {
    if ('function' === typeof addCat) {
      addCat('Mr. Whiskers');
    }
  });
</script>

{#if catList.length}
  <ul>
    {#each catList as cat}
      <li>
        {cat.name}
      </li>
    {/each}
  </ul>
{:else}
  You don't have any cats :(
{/if}

Here’s a basic Svelte component. It accepts a property called catList, and addCat.

catList is an array of cats with names.

addCat will be a function that make a dispatch call to Redux, to add a cat to the store.

Every time a new cat gets added, it will update the catList prop in the Svelte component and update the output.


addCat(name)

addCat will accept a string value parameter which will be the given cat name.

Before the <script> tag ends, I’m using the onMount Svelte hook to add my cat, Mr. Whiskers.


onMount(() => {
  if ('function' === typeof addCat) {
    addCat('Mr. Whiskers');
  }
});

In the HTML render I’m doing an if block conditional to see if there are any items in the array, catList.

If catList does have items, it will iterate over it and create a list item element that displays the name of the cat.

svelte-redux-connect is a HOC (higher-order component), and there’s really no way to wrap a HOC inside a Svelte file.

This is where a JS file is needed. I’m going to connect the Svelte component, CatList, to the Redux store.

Inside cat-list.js I’ll add the following code.


import { connect } from 'svelte-redux-connect';

// Import Svelte component
import CatList from './cat-list.svelte';

const mapDispatchToProps = dispatch => ({

  // Add `addCat` function
  addCat: (catName) => dispatch({
    type: 'ADD_CAT',
    payload: { name: catName },
  }),

});

// Get list of cats and pass to Svelte component
const mapStateToProps = state => ({
  cats: state.cats.list,
});

export default connect(mapStateToProps, mapDispatchToProps)(CatList);

Code breakdown!

First I’m importing my Svelte component, CatList. We can do this in Svelte because a Svelte component is just a JavaScript constructor.

I’m also importing the HOC utility, connect, from svelte-redux-connect library.


const mapDispatchToProps = dispatch => ({
  addCat: (catName) => dispatch({
    type: 'ADD_CAT',
    payload: { name: catName },
  })
});

const mapStateToProps = state => ({
  catList: state.cats.list,
});

The next important snippet of code are the variable functions that are mapping the Redux store, and dispatch function to the Svelte component.

Finale

So far I’ve:

The only thing that is left is to use the CatList component inside the App component, so I can see the output.

I will update the App.js file to import the cat-list.js file.


<script>
  import { Provider } from 'svelte-redux-connect';

  import store from './store.js';

  import CatList from './cat-list';
</script>

<Provider {store}>
  <CatList />
</Provider>

That’s it!

We have created a Svelte application that is utilizing the Redux state management library.