How to create Redux Store only with VanillaJS and RxJS

How to create Redux Store only with VanillaJS and RxJSGuy ChabraBlockedUnblockFollowFollowingApr 16In this guide, we’re going to build Redux Store architecture using only VanillaJS and RxJS.

Yes, we’ll NOT use React at all.

Before you attempt this guide, you should have:Good knowledge in VanillaJS.

Basic knowledge in RxJS.

Basic knowledge in TypeScript, HTML, Scss.

First, what is Redux Store?According to redux.

js Redux Store is “A predictable state container for JavaScript apps.

”.

Well, that’s pretty much it.

Your application got some global state which holds everything that you need.

You can read its data across your application, listen to changes, and mutate its content via so-called Actions, Reducers and Epics.

Actions are objects which describe what’s need to be changed in the state or what task we would like to perform, while Reducers are the implement of how to mutate the state in a synchronized way.

But don’t be worry, everything will be explained in details later on.

In general Redux attempts to make state mutations more predictable by imposing certain restrictions on how and when updates can happen.

Benefits of using Redux Store architecture:Single source of truth — data has only one official source to be used by data consumers.

Separation of concern — which lead to reusable pieces of code, and make changes much easier.

Low coupling & High cohesion — every component in this architecture has its own purpose and there is absolutely no coupling between each other.

That's actually leading to Separation of concern.

High scalability — extending this architecture to a bigger scale is very easy.

Simple and clean — well that’s exactly what you will see after finish reading this guide.

Easy to debugThe drawbacks of Redux Store architecture:Increased layering complexity in writing state manipulation logic like Actions and Reducers.

Not very useful for small apps.

Let’s start codingBy the end of this guide, we will achieve a fully functional Redux Store architecture implemented only with VanillaJS and RxJS.

The application will have some basic user-interface that allows us to request some posts, echo them and delete every item.

Again we will NOT use ReactJS.

Project files structure- src/ – store/ – epics/ – delete-post.

epic.

ts – get-posts.

epic.

ts – index.

ts – reducers/ – delete-post-request.

reducer.

ts – delete-post-success.

reducer.

ts – get-posts-success.

reducer.

ts – index.

ts – store.

actions.

ts – store.

epics.

ts – store.

init.

ts – store.

reducer.

ts – store.

types.

ts – store.

utils.

ts – index.

js – styles.

scss – utils.

ts- index.

html- package.

json- tsconfig.

jsonSo before we start diving into the code, as I always recommend, let’s first define the types & interfaces that will be used throughout our application.

Once we covered that, we will be able to speak the same language.

Types/store/store.

types.

ts[Interface] ApplicationState — In the ApplicationState Interface, we declare what data will be stored in our state.

In this toy application, we will have a dictionary of posts where the key is the post id and its value is the actual instance.

In addition, we will need another dictionary with the same key to a boolean value this time, which indicates that this post is currently being deleted (async action).

[Type] Reducer —AReducer specify how the application’s state changes in response to actions.

Or in other words, given the previous application state and the dispatched action (which holds a type and some payload), the reducer will return the newly updated state in a synchronized way.

[Type] Epic —Epic is a function which takes an Observable of actions and returns an Observable of actions.

Actions in, actions out.

They let us write async logic that interacts with the store.

[Type] ActionCreator — ActionCreator is a function definition that can take any number of arguments and must return an Action.

We will use action creators, well, as you guessed to create actions.

[Interface] Action — Action contain a type and a payload which is optional, so the Reducer will know what logic to run, and what data needs to be replaced.

[Type] Dispatch — The Dispatch function, very simple, just fires an action.

[Type] StoreSubscriber — That's the regular RxJS subscriber, just forcing a type of ApplicationState.

For the curious of us, that’s the definition of NextObserver .

/** OBSERVER INTERFACES */export interface NextObserver<T> { closed?: boolean; next: (value: T) => void; error?: (err: any) => void; complete?: () => void;}export class Observable<T> implements Subscribable<T> {.

subscribe( next?: (value: T) => void, error?: (error: any) => void, complete?: () => void) : Subscription;.

}That’s not really important… don’t waste more than a minute on that.

[Interface] Store — well yes, that's the Store, we need a way to dispatch actions, and to subscribe to its changes.

UtilsHere are some utility functions we are going to use.

/store/store.

utils.

ts/utils.

tsActionsThis application as mentioned earlier will support 2 use-cases:The user will be able to get a list of 100 posts by a press of a button.

Those will be printed to the screen.

The user will be able to delete any post he wants.

So let’s review our actions file.

/store/store.

actions.

tsIn Redux we need to define 2 actions for every single async action we would like to perform (if we are dependent on its response of course) since the reducer is updating the state synchronously.

The first will cause an Epic to perform some network request or async logic, and the second is used by the epic to fire the resolved data once the logic is done.

We are handling async jobs in a synchronized way.

ReducersSince we are already created the interface of the ApplicationState .

We can start writing our reducers.

We will need 3 reducers:Get posts success — will handle the update of getPostsSuccess action.

Delete post request reducer — will handle the update of deletePostRequest action.

Delete post success reducer — will handle the update of deletePostSuccess action.

/store/reducers/get-posts-success.

reducer.

ts/store/reducers/delete-post-request.

reducer.

ts/store/reducers/delete-post-success.

reducer.

ts/store/reducers/index.

tsCreating the Root ReducerThe root reducer will define the initial application state, and for each dispatched action will execute the relevant reducer that we just created according to the type of the action.

Otherwise, the previous application state will be returned.

EpicsAs said earlier “actions in, actions out”.

They let us write async logic that interacts with the store.

The actions that will be returned from an epic will be automatically dispatched.

We will need 2 epics in our toy application:Get posts epic — will handle the async task of reaching the API to get an array of 100 posts.

Delete post epic — will handle the async task of reaching the API to delete a single post.

/store/epics/get-all-posts.

epic.

ts/store/epics/delete-post.

epic.

ts/store/epics/index.

tsCombine the Epics into a single Observable/store/store.

epics.

tsFinally, createStoreThis function creates the application store, setup our reducers, epics and an observable of actions.

/store/store.

init.

tsLet’s walk through command by command:Create a Subject of Actions.

// Create the Action Subjectconst action$ = new Subject<Action>();2.

Create the state and attach the reducer to the scan rxjs operator.

Each dispatched action will be reduced by the reducer.

const state$ = action$.

pipe( startWith({ type: "@@INIT" }), scan(reducer, undefined) // <– The magic happens here);scan works like Array.

reduce but over time:/**Applies an accumulator function over the source Observable, and returns each intermediate result, with an optional seed value**/scan(accumulator: function, seed: any): ObservableYou can see some examples here:https://www.

learnrxjs.

io/operators/transformation/scan.

html3.

Connect our Epics to the StoreEach epic will get the stream of actions and will dispatch other actions in return.

The emitted actions will be immediately dispatched through the normal store.

dispatch().

combineEpics(action$, state$).

subscribe(action$);4.

Return the Storereturn { dispatch: action$.

next.

bind(action$), subscribe: state$.

subscribe.

bind(state$)};Our HTMLSimply a button to get all posts, and a placeholder to echo out the posts from the application state.

/index.

htmlThe MainPlay with itConclusionWell, that’s it, we have built Redux Store architecture using only VanillaJS and RxJS.

In this article I wanted to show you the power of using RxJS, and what can we achieve using its tools.

This guide is heavily inspired by Redux-Observable.

I use this package very often in large scale applications.

If you liked this guide you should definitely take a look at this package.

Thank you for reading,I would appreciate comments and questions.

.

. More details

Leave a Reply