Recoding Redux
In this article you’re going to see, in a simplified way, what’s hidden behind Redux and store creation.
First of all, a reminder is required.
This library allows you to have a predictable and immutable state container at your disposal for your JS application. Be careful though, it is not preferable to use Redux in any situation, even if it considerably improves the organization of the state of this one. You should first ask yourself if Redux is appropriate for your application:
- Do I need a reasonable amounts of data changing over time
- Do I need a single source of truth for my state
- Keeping all your state in a top-level component is no longer sufficient
Setup
Let’s see together the creation of our container, our store.
(A Todo List App is at your disposal, you can fork it or created your own app).
Prototype
In order to create our store, Redux makes available to us the createStore()
method, which takes three arguments:
- A state
reducer
, which returns the next state, given the current state and the action to handle - An optional
preloadedState
, which is the initial state - An optional
enhancer
, not really necessary for this article
And returns our store, as an object, containing three methods as getState
, subscribe
, and dispatch
/* Todo List App - myRedux.js */function createStore(reducer, preloadedState = {}) {
const getState;
const subscribe;
const dispatch;
return { getState, subscribe, dispatch };
}
Get State
createStore
first initialize our current state with the preloadedState
and create a state get method, getState
, which takes nothing as a parameter and return the current state:
/* Todo List App - myRedux.js */function createStore(reducer, preloadedState = {}) {
// Initialized State
let state = preloadedState;
const getState = () => state;
/* ... */
return { getState, subscribe, dispatch };
}
Subscribe (and unsubscribe)
Then, createStore
create an empty list of listeners and a method to subscribe
to the events of the store, which takes a callback to call at an event and returns the associated unsubscribe
method.
/* Todo List App - myRedux.js */function createStore(reducer, preloadedState = {}) {
/* ... */ // Initialized Listener list
const listeners = [];
const subscribe = listener => {
// Save callback listener in our list
listeners.push(listener); // return unsubscribe method
return function unsubscribe() {
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
}
}; /* ... */ return { getState, subscribe, dispatch };
}
Dispatch
Finally, createStore
create a method to dispatch
an action, in order to call the state reducer and, maybe, update our state. This one takes an action as an argument. It also triggers all subscriptions.
/* Todo List App - myRedux.js */function createStore(reducer, preloadedState = {}) {
/* ... */ // Dispatch action by calling reducer method
// and call all listeners callback
const dispatch = action => {
state = reducer(state, action);
listeners.forEach(listener => listener());
} return { getState, subscribe, dispatch };
}
Full implementation
That’s all for createStore
function. As you can see, it’s easy to understand how it works, in a simplified way. Here is the full implementation of createStore
with everything we saw above:
/* Todo List App - myRedux.js */function createStore(reducer, preloadedState = {}) {
// Initialized State
let state = preloadedState;
const getState = () => state; // Initialized Listener list
const listeners = [];
const subscribe = listener => {
// Save callback listener in our list
listeners.push(listener); // return unsubscribe method
return function unsubscribe() {
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
}
}; // Dispatch action by calling reducer method
// and call all listeners callback
const dispatch = action => {
state = reducer(state, action);
listeners.forEach(listener => listener());
} return { getState, subscribe, dispatch };
}
Usage
I now invite you to to use your own createStore
and see if all your app still work well:
/* Todo List App - index.js */import React from 'react';
import ReactDOM from 'react-dom';// import { createStore } from 'redux';import { Provider } from 'react-redux';import { createStore } from './myRedux';
import { todos } from './reducers/index';import App from './components/App.jsx';
import './styles.css';const initialState = [];
const store = createStore(todos, initialState);const unsubscribe = store.subscribe(() =>
console.log(store.getState()));ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'),
);
Sacha Brami, developer at Abbeal