Juin Chiu
2 min readNov 10, 2016

ref: redux/src/createStore.js

What is Store in Redux?

Redux is a predictable state container. It also needs to provide some way to change the state, subscribe some callback functions, or provides some observables. Store is there to serve for these purposes. For example:

store.getState() // => Get current state
store.dispatch(action) // => Dispatch action to change the state
store.subscribe(function) // => Subscribe to hook some callbacks after dispatching
store.replaceReducer(reducer) // => Replace reducer

Show me the code!

Let’s see the implementation of dispatch for example:

export default function createStore(reducer, preloadedState, enhancer) {
var currentReducer = reducer
var currentState = preloadedState
var currentListeners = []
var nextListeners = currentListeners
var isDispatching = false

function dispatch(action) {
if (!isPlainObject(action)) {
throw new Error(
'Actions must be plain objects. ' +
'Use custom middleware for async actions.'
)
}

if (typeof action.type === 'undefined') {
throw new Error(
'Actions may not have an undefined "type" property. ' +
'Have you misspelled a constant?'
)
}

try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}

var listeners = currentListeners = nextListeners
for (var i = 0; i < listeners.length; i++) {
var listener = listeners[i]
listener()
}

return action
}

return {
dispatch
}
}

What things are going on is quite straightforward here: First, validate action object; Then, pass state and action into reducer, and save the returned state; Finally, trigger every listener in the store, and return action. Done!

And again, let’s use ruby to implement this (only essential parts):

module Rubidux
class Store
attr_accessor :state
attr_accessor :reducer
attr_accessor :listeners
attr_accessor :dispatch
attr_accessor :subscribe

def initialize(reducer, preload_state, enhancer = nil)
raise ArgumentError.new("Expect reducer to be a Proc.") unless reducer.is_a? Proc
enhancer(Rebidux::Store).(reducer, preload_state) if enhancer
@state = preload_state || {}
@listeners = []
@reducer = reducer
@dispatch = _dispatch
@subscribe = _subscribe
end

private

def _dispatch
-> (action) {
raise ArgumentError.new("Expect action to have key 'type'.") unless action[:type]
@state = @reducer.(@state, action)
@listeners.each(&:call)
action
}
end

def _subscribe
-> (listener) {
raise ArgumentError.new("Expect listener to be a Proc.") unless listener.is_a? Proc
@listeners.push listener
-> { @listeners.delete listener }
}
end
end
end

Ruby is amazingly elegant!

Juin Chiu
Juin Chiu

Written by Juin Chiu

Blockchain researcher, dev, co-organizer of Taipei Ethereum Meetup, focusing on consensus protocol, self-sovereign identity and anonymity network.

No responses yet