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:
- Installed dependencies
- Create a redux store
- Create a reducer
- Added Redux to the Svelte application
- Connected a Svelte component to Redux store
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.
I like to tweet about Svelte and post helpful code snippets. Follow me there if you would like some too!