This is a code example of Redux with only HTML & pure JavaScript. Code sandbox
<!DOCTYPE html>
<html>
<head>
<title>Redux basic example</title>
<script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script>
</head>
<body>
<div>
<p>
Clicked: <span id="value">0</span> times
<button id="increment">+</button>
<button id="decrement">-</button>
<button id="incrementIfOdd">Increment if odd</button>
<button id="incrementAsync">Increment async</button>
</p>
</div>
<script>
function counter(state, action) {
if (typeof state === 'undefined') {
return 0
}
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
var store = Redux.createStore(counter)
var valueEl = document.getElementById('value')
function render() {
valueEl.innerHTML = store.getState().toString()
}
render()
store.subscribe(render)
document.getElementById('increment')
.addEventListener('click', function () {
store.dispatch({ type: 'INCREMENT' })
})
document.getElementById('decrement')
.addEventListener('click', function () {
store.dispatch({ type: 'DECREMENT' })
})
document.getElementById('incrementIfOdd')
.addEventListener('click', function () {
if (store.getState() % 2 !== 0) {
store.dispatch({ type: 'INCREMENT' })
}
})
document.getElementById('incrementAsync')
.addEventListener('click', function () {
setTimeout(function () {
store.dispatch({ type: 'INCREMENT' })
}, 1000)
})
</script>
</body>
</html>
-
createStore&counterReducer
// Counter reducer
function counterReducer(state, action) {
if (typeof state === 'undefined') {
return 0;
}
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
// Create store
var store = Redux.createStore(counterReducer);
-
createStorereceives acounterReducerfunction as a param and return an object called store. - This is the diagram of createStore function with mental model as a class.
Here is simplified version of createStore in redux source code:
function createStore(reducer, initialState) {
var currentReducer = reducer;
var currentState = initialState;
var listeners = [];
var isDispatching = false;
function getState() {
return currentState;
}
function subscribe(listener) {
listeners.push(listener);
return function unsubscribe() {
var index = listeners.indexOf(listener);
listeners.splice(index, 1);
};
}
function dispatch(action) {
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.');
}
try {
isDispatching = true;
currentState = currentReducer(currentState, action);
} finally {
isDispatching = false;
}
listeners.slice().forEach(listener => listener());
return action;
}
function replaceReducer(nextReducer) {
currentReducer = nextReducer;
dispatch({ type: '@@redux/INIT' });
}
dispatch({ type: '@@redux/INIT' });
return { dispatch, subscribe, getState, replaceReducer };
}
-
currentReducer=counterReducer -
currentState=preloadedSate - When store is created, it initially
dispatchwith action type is'@@redux/INIT'so that every reducer returns their initial state. In casecounterReducer, it returns0
What happens inside dispatch function ?
// Dispatch function inside Redux store
function dispatch(action: A) {
currentState = currentReducer(currentState, action)
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
}
- The function
currentReduceris called which iscounterReducer - Because action type is
@@redux/INITandcurrentStateisundefined, socounterReducerreturns0as default value which is the initial state of the store. - Now,
currentStateis0 - After updating the state with initial value, it calls all listeners that is subscribing the store to notify.
var valueEl = document.getElementById('value')
function render() {
valueEl.innerHTML = store.getState().toString()
}
render()
store.subscribe(render)
- In this case, we have
render()function, it is called back and update the DOM element with the initial value. - Now in the browser, we will se the number
0shown.
Updating state when action is sent
document.getElementById('increment')
.addEventListener('click', function () {
store.dispatch({ type: 'INCREMENT' })
})
- When users click on the button "+", store dispatches the action with type
'INCREMENT'to the reducer of the store and the flow is the same as explanation above. - Function
currentReduceris called with state is0and action's type is'INCREMENT'. - Because
'INCREMENT'is a case insidecounterReducerfunction, so the new state now is equal to0 + 1and returned to the state of the store. - Next, again it notifies listeners to let them know state is updated successfully.
- Now, in the screen we will see Clicked: 1 times
- The flow is similar to other action types
So this is basically how Redux works under the hood. In real life project, Redux store may have multiple reducers and midleware, and 3rd-party libraries enhance Redux workflow. But at very its core that's how it works basically !

Top comments (3)
I use index.js file that contains in script tags codes. However, getting error Redux.create is not a function.
Try this link codesandbox.io/s/github/reduxjs/re...
I want to create a another js file for script tag but getting error. I don't want to any script code in index.html but unpkg.com/redux@latest/dist/redux.... isn't reached other js file