Skip to content

Instantly share code, notes, and snippets.

@markerikson
Last active December 28, 2021 09:23
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markerikson/0383775096f2b32e48ad41499cf8a1fb to your computer and use it in GitHub Desktop.
Save markerikson/0383775096f2b32e48ad41499cf8a1fb to your computer and use it in GitHub Desktop.
Redux array batched actions enhancer
// copy-pasta'd from isarray
var toString = {}.toString;
const isArray = Array.isArray || function (arr) {
return toString.call(arr) == '[object Array]';
};
export function batchedSubscribe() {
let currentListeners = [];
let nextListeners = currentListeners;
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice();
}
}
function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error('Expected listener to be a function.');
}
let isSubscribed = true;
ensureCanMutateNextListeners();
nextListeners.push(listener);
return function unsubscribe() {
if (!isSubscribed) {
return;
}
isSubscribed = false;
ensureCanMutateNextListeners();
const index = nextListeners.indexOf(listener);
nextListeners.splice(index, 1);
};
}
function notifyListeners() {
const listeners = currentListeners = nextListeners;
for (let i = 0; i < listeners.length; i++) {
listeners[i]();
}
}
return next => (...args) => {
const store = next(...args);
const subscribeImmediate = store.subscribe;
function dispatch(action) {
const actionIsArray = isArray(action);
const result = actionIsArray ? action.map(store.dispatch) : store.dispatch(action);
notifyListeners();
return result;
}
return {
...store,
dispatch,
subscribe,
subscribeImmediate
};
};
}
<!DOCTYPE html>
<html>
<head>
<title>Redux basic example</title>
<script src="https://npmcdn.com/redux@latest/dist/redux.min.js"></script>
<script src="reduxThunk.js"></script>
<script src="reduxBatchedDispatch.js"></script>
</head>
<body>
<div>
<p>
Clicked: <span id="value">0</span> times
<button id="increment">+</button>
<button id="decrement">-</button>
<button id="doubleIncrement">Double Increment</button>
<button id="doubleIncrementThunk">Double Increment (thunk)</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 thunkMiddleware = createThunkMiddleware();
var batchedSubscribeEnhancer = batchedSubscribe();
var middlewareEnhancer = Redux.applyMiddleware(thunkMiddleware);
var composedEnhancers = Redux.compose(middlewareEnhancer, batchedSubscribeEnhancer);
var store = Redux.createStore(counter, undefined, composedEnhancers)
var valueEl = document.getElementById('value')
function render() {
valueEl.innerHTML = store.getState().toString()
}
render()
store.subscribe(render)
var notificationCounter = 0;
store.subscribe(function() {
notificationCounter += 1;
console.log("Notifications: ", notificationCounter);
});
document.getElementById('increment')
.addEventListener('click', function () {
store.dispatch({ type: 'INCREMENT' })
})
document.getElementById('decrement')
.addEventListener('click', function () {
store.dispatch({ type: 'DECREMENT' })
})
document.getElementById('doubleIncrement')
.addEventListener('click', function () {
store.dispatch([
{ type: 'INCREMENT' },
{ type: 'INCREMENT' }
])
})
document.getElementById('doubleIncrementThunk')
.addEventListener('click', function () {
var thunk = function(dispatch, getState) {
dispatch([
{ type: 'INCREMENT' },
{ type: 'INCREMENT' }
])
}
store.dispatch(thunk);
})
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>
'use strict';
/*
exports = exports || {};
Object.defineProperty(exports, "__esModule", {
value: true
});
*/
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
//exports.batchedSubscribe = batchedSubscribe;
// copy-pasta'd from isarray
var toString = {}.toString;
var isArray = Array.isArray || function (arr) {
return toString.call(arr) == '[object Array]';
};
function batchedSubscribe() {
var currentListeners = [];
var nextListeners = currentListeners;
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice();
}
}
function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error('Expected listener to be a function.');
}
var isSubscribed = true;
ensureCanMutateNextListeners();
nextListeners.push(listener);
return function unsubscribe() {
if (!isSubscribed) {
return;
}
isSubscribed = false;
ensureCanMutateNextListeners();
var index = nextListeners.indexOf(listener);
nextListeners.splice(index, 1);
};
}
function notifyListeners() {
var listeners = currentListeners = nextListeners;
for (var i = 0; i < listeners.length; i++) {
listeners[i]();
}
}
return function (next) {
return function () {
var store = next.apply(undefined, arguments);
var subscribeImmediate = store.subscribe;
function dispatch(action) {
var actionIsArray = isArray(action);
var result = actionIsArray ? action.map(store.dispatch) : store.dispatch(action);
notifyListeners();
return result;
}
return _extends({}, store, {
dispatch: dispatch,
subscribe: subscribe,
subscribeImmediate: subscribeImmediate
});
};
};
}
function createThunkMiddleware(extraArgument) {
return function (_ref) {
var dispatch = _ref.dispatch;
var getState = _ref.getState;
return function (next) {
return function (action) {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
};
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment