Create your own Redux with RxJS
Basic concepts of reactivity and the RxJS library, and how the Redux store can be implemented using RxJS.
Author

Date

Book a call
Reactivity.
Reactive programming is something you might have heard of, but might not know how to approach yet. In very simple words, it's a programming paradigm like 'Functional programming' or 'Object-oriented programming' which focuses on a different aspect, namely, how to write programs that automatically do something when something else happens.
Event handlers in JS are naturally reactive and demonstrate this well:
const someDiv = document.getElementById('my-div')
function handleClick() {
doSomeFancyStuff()
}
someDiv.addEventListener('click', handleClick)
They listen for events and automatically trigger a handler (in this case handleClick) when the event happens, which in turn does something (in this case, some fancy stuff).
In fact events are a nice way to model things that are yet to happen or finish (like asynchronous code returning a value).
A Note on Sequences:
An array is the simplest kind of collection of data. It is a sequence of things; which is as simple as a collection can get.
Arrays provide ways to deal with collections easily. You are probably familiar with loops that let you process an array by iterating over its elements.
Also, many languages like JavaScript, provide higher order functions like map and filter, that let you pass a function that will be applied to each element in the array.
Adding 2 to an array of numbers is easy with Array.prototype.map
const arrayOfNumbers = [1, 2, 3, 4]
const add2 = x => x + 2
const arrayOfSlightlyBiggerNumbers = arrayOfNumbers.map(add2)
Array.prototype.map returns a new array and does not mutate the old one. Moreover, the array prototype methods can be chained.
const todoList = [
{ id: 1, text: 'Learn ES6', done: true },
{ id: 2, text: 'Learn RxJS', done: false },
{ id: 3, text: 'Buy groceries', done: false },
]
const isCompleted = todo => todo.done
const getTodoText = todo => todo.text
const startsWithLearn = text => text.startsWith('Learn')
const completedLearningTaskCount = todoList
.filter(isCompleted)
.map(getTodoText)
.filter(startsWithLearn)
.length
These two facts let us deal with arrays in a clean, declarative and functional way.
Wouldn't it be great if we had a way to deal with events and asynchronous operations in a clean and familiar way, much similar to the one mentioned above?
Well, this is exactly what ReactiveX does. ReactiveX is a language independent specification that describes an API (functions and interfaces) that helps us deal with all sorts of things by treating them as sequences of events.
RxJS is the JavaScript implementation of ReactiveX.
Why ReactiveX matters.
ReactiveX lets us model just about everything as a stream of events.
An event stream is very similar to an array, except it's asynchronous. So each element in the stream arrives as and when it is generated.
A sequence of mouse clicks can easily be visualised as an event stream.

So can an API call, although it is a stream of a single event. And even regular arrays!
In the end, ReactiveX and RxJS provide a uniform way to deal with asynchronous and synchronous data using a huge number of functions called operators.
RxJS Concepts.
RxJS is a huge library, and is slightly intimidating. It can be overwhelming to go through the documentation and figure out where to start.
This article aims to give you the bare minimum information to get quickly started with RxJS, and hopefully to absorb the idea and whole point of reactivity.
So here goes.
RxJS has four things at its core:
- Observables are streams (or sequences) of events.
- Subscriptions trigger code when an observable generates a new event (addEventListener behaves like a subscription in this way).
- Observers are what subscribe to the observable (usually they take the form of a handler, or a function, just like the click handler handleClick we saw earlier).
- Operators are functions which process each event coming from the observable and generate a new observable stream in the process (a bit like map, filter, reduce and other higher order functions).
And that's it. That's the core of RxJS.
This sandbox demonstrates all four of these things. It creates an observable from the clicks coming from a button.
Some Advanced Concepts.
Apart from the four concepts we saw earlier, you'll need to know a couple more things before implementing you own Redux store implementation:
A Subject is like an Observable in many ways, but provides a way for multiple observers to listen easily. Think of them as event emitters.
BehaviourSubject is exactly like a Subject, except it stores the last emitted event. So you could consider it to be stateful.
This statefulness is exactly what we need to implement Redux's store.
And finally, the part you've been waiting for
Redux is a popular state management library, whose main philosophy is that an app's state must come from a single source of truth, named the store.
The store in Redux provides three methods:
Let's try to implement the store and this API using RxJS. We'll use BehaviourSubject to do that.
Let's start off with a class to define our store interface.
class Store {
constructor(reducer, initialState) {
this.state = initialState
this.reducer = reducer
}
// Gives us the state at that instant
getState = () => {}
// Takes an action and causes a change in the store state
dispatch = (action) => {}
//Calls the observer whenever the state changes
subscribe = (observer) => {}
}Let's first initialise the state. Since we're using BehaviourSubject, we just initialise the state to a new BehaviourSubject with the initial state
constructor(reducer, initialState) {
this.state = newBehaviourSubject(initialState)
this.reducer = reducer
}The state of the BehaviourSubject at any given time can be retrieved easily using the value property. This gives us a natural way to implement getState
getState = () => {
this.state.value
}The dispatch is a bit more complex. It takes an action and changes the state according to the reducer. So we can get the next state by calling the reducer with the action. We can then update the state by calling BehaviourSubject.next
dispatch = (action) => {
const nextState = this.reducer(this.getState(), action)
this.state.next(nextState)
}The subscribe method is almost as simple as getState. Since one can easily subscribe to a BehaviourSubject by using its subscribe method, we do just that.
subscribe = (observer) => {
this.state.subscribe(observer)
}And that's it!
We have created a class that defines the Redux store.
Here's the full implementation, used in a simple todo list app written in React. Notice how I just replace Redux's createStore with my own, and everything just works.
It's important to note that a lot of error handling and special cases have been ignored here, but it really showcases how powerful RxJS can be.
Conclusion
Reactive programming is an incredibly powerful programming model and can help us deal with something as complex as event handling with ease.
RxJS is a library that helps us write apps in such a way. It's powerful enough to let you implement your own Redux store, or any other state management mechanism with it.
It's also worth noting that the reason I was able to swap in my own store so easily in the todo app is because Redux's own API is simple and well defined. Good API design can go a long way in making maintainable software that may require you to swap out components in favour of others that better suit the changing requirements.
Further reading
Book a Discovery Call
Related Articles.
More from the engineering frontline.
Dive deep into our research and insights on design, development, and the impact of various trends to businesses.

Apr 9, 2026
From RFPs to Revenue: How We Built an AI Agent Team That Writes Technical Proposals in 60 Seconds
GeekyAnts built DealRoom.ai — four AI agents that turn RFPs into accurate technical proposals in 60 seconds, with real-time cost breakdowns and scope maps.

Apr 6, 2026
How We Built an AI System That Automates Senior Solution Architect Workflows
Discover how we built a 4-agent AI co-pilot that converts complex RFPs into draft technical proposals in 15 minutes — with built-in conflict detection, assumption surfacing, and confidence scoring.

Apr 6, 2026
AI Code Healer for Fixing Broken CI/CD Builds Fast
A deep dive into how GeekyAnts built an AI-powered Code Healer that analyzes CI/CD failures, summarizes logs, and generates code-level fixes to keep development moving.

Apr 2, 2026
A Real-Time AI Fraud Decision Engine Under 50ms
A deep dive into how GeekyAnts built a real-time AI fraud detection system that evaluates transactions in milliseconds using a hybrid multi-agent approach.

Apr 1, 2026
Building an Autonomous Multi-Agent Fraud Detection System in Under 200ms
GeekyAnts built a 5-agent fraud detection pipeline that makes decisions in under 200ms — 15x cheaper than single-model systems, with full explainability built in.

Mar 31, 2026
Building a Self-Healing CI/CD System with an AI Agent
When code breaks a pipeline, developers have to stop working and figure out why. This blog shows how an AI agent reads the error, finds the fix, and submits it for review all on its own.