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);
-
createStore
receives acounterReducer
function 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
dispatch
with 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
currentReducer
is called which iscounterReducer
- Because action type is
@@redux/INIT
andcurrentState
isundefined
, socounterReducer
returns0
as default value which is the initial state of the store. - Now,
currentState
is0
- 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
0
shown.
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
currentReducer
is called with state is0
and action's type is'INCREMENT'
. - Because
'INCREMENT'
is a case insidecounterReducer
function, so the new state now is equal to0 + 1
and 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