Instantly share code, notes, and snippets.

Embed
What would you like to do?
Redux without the sanity checks in a single file. Don't use this, use normal Redux. :-)
function mapValues(obj, fn) {
return Object.keys(obj).reduce((result, key) => {
result[key] = fn(obj[key], key);
return result;
}, {});
}
function pick(obj, fn) {
return Object.keys(obj).reduce((result, key) => {
if (fn(obj[key])) {
result[key] = obj[key];
}
return result;
}, {});
}
function bindActionCreator(actionCreator, dispatch) {
return (...args) => dispatch(actionCreator(...args));
}
export function bindActionCreators(actionCreators, dispatch) {
return typeof actionCreators === 'function' ?
bindActionCreator(actionCreators, dispatch) :
mapValues(actionCreators, actionCreator =>
bindActionCreator(actionCreator, dispatch)
);
}
export function compose(...funcs) {
return arg => funcs.reduceRight((composed, f) => f(composed), arg);
}
export function applyMiddleware(...middlewares) {
return (next) => (reducer, initialState) => {
var store = next(reducer, initialState);
var dispatch = store.dispatch;
var chain = [];
chain = middlewares.map(middleware => middleware({
getState: store.getState,
dispatch: (action) => dispatch(action)
}));
dispatch = compose(...chain)(store.dispatch);
return { ...store, dispatch };
};
}
export function combineReducers(reducers) {
var finalReducers = pick(reducers, (val) => typeof val === 'function');
return (state = {}, action) => mapValues(finalReducers,
(reducer, key) => reducer(state[key], action)
);
}
export 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 };
}
@RickWong

This comment has been minimized.

Show comment
Hide comment
@RickWong

RickWong Sep 22, 2015

Genius is not measured in LOC.

RickWong commented Sep 22, 2015

Genius is not measured in LOC.

@davidpelayo

This comment has been minimized.

Show comment
Hide comment
@davidpelayo

davidpelayo commented Sep 22, 2015

Brilliant

@omnidan

This comment has been minimized.

Show comment
Hide comment
@omnidan

omnidan Sep 26, 2015

I was mind-blown when someone asked me how redux-thunk worked and I checked the code only to realize it has 6 lines in total. This blew my mind even more 😅

omnidan commented Sep 26, 2015

I was mind-blown when someone asked me how redux-thunk worked and I checked the code only to realize it has 6 lines in total. This blew my mind even more 😅

@snehesht

This comment has been minimized.

Show comment
Hide comment
@snehesht

snehesht commented Oct 5, 2015

Awesome.

@dbrans

This comment has been minimized.

Show comment
Hide comment
@dbrans

dbrans Oct 13, 2015

@gaearon, In the current revision, in applyMiddleware, the initial value of var dispatch = store.dispatch is never used. Did you meant to use it on line 43?
https://gist.github.com/gaearon/ffd88b0e4f00b22c3159/4c9a62c6a2b353842dd2b6d15b9ca363ad4161e3#file-slim-redux-js-L36

dbrans commented Oct 13, 2015

@gaearon, In the current revision, in applyMiddleware, the initial value of var dispatch = store.dispatch is never used. Did you meant to use it on line 43?
https://gist.github.com/gaearon/ffd88b0e4f00b22c3159/4c9a62c6a2b353842dd2b6d15b9ca363ad4161e3#file-slim-redux-js-L36

@davidjnelson

This comment has been minimized.

Show comment
Hide comment
@davidjnelson

davidjnelson Oct 25, 2015

I love this :-) I think redux has the highest GitHub stars per line of code of all time. 80 stars per line ;-)

davidjnelson commented Oct 25, 2015

I love this :-) I think redux has the highest GitHub stars per line of code of all time. 80 stars per line ;-)

@dlwalsh

This comment has been minimized.

Show comment
Hide comment
@dlwalsh

dlwalsh Oct 27, 2015

Is there a reason why mapValues (and also pick) looks like this:

function mapValues(obj, fn) {
  return Object.keys(obj).reduce((result, key) => {
    result[key] = fn(obj[key], key);
    return result;
  }, {});
}

and not the more idiomatic:

function mapValues(obj, fn) {
  return Object.keys(obj).reduce((result, key) => (
    Object.assign({}, result, {
      [key]: fn(obj[key], key);
    });
  ), {});
}

Is it a case of performance over purity?

dlwalsh commented Oct 27, 2015

Is there a reason why mapValues (and also pick) looks like this:

function mapValues(obj, fn) {
  return Object.keys(obj).reduce((result, key) => {
    result[key] = fn(obj[key], key);
    return result;
  }, {});
}

and not the more idiomatic:

function mapValues(obj, fn) {
  return Object.keys(obj).reduce((result, key) => (
    Object.assign({}, result, {
      [key]: fn(obj[key], key);
    });
  ), {});
}

Is it a case of performance over purity?

@ksmithbaylor

This comment has been minimized.

Show comment
Hide comment
@ksmithbaylor

ksmithbaylor Nov 25, 2015

@dlwalsh or for that matter:

function mapValues(obj, fn) {
  return Object.keys(obj).reduce((result, key) => ({
    ...result,
    [key]: fn(obj[key], key)
  }), {});
}

ksmithbaylor commented Nov 25, 2015

@dlwalsh or for that matter:

function mapValues(obj, fn) {
  return Object.keys(obj).reduce((result, key) => ({
    ...result,
    [key]: fn(obj[key], key)
  }), {});
}
@acusti

This comment has been minimized.

Show comment
Hide comment
@acusti

acusti Dec 1, 2015

@dbrans The initial dispatch function in applyMiddleware is used on line 41 within the body of the wrapped dispatch (i.e. next) function passed to each middleware.

acusti commented Dec 1, 2015

@dbrans The initial dispatch function in applyMiddleware is used on line 41 within the body of the wrapped dispatch (i.e. next) function passed to each middleware.

@CrocoDillon

This comment has been minimized.

Show comment
Hide comment
@CrocoDillon

CrocoDillon Jan 21, 2016

@dlwalsh, result is created inside the mapValues function and passed to reduce as initial value (also called an accumulator). Because it’s created inside mapValues, it can be mutated and mapValues would still be a pure function.

CrocoDillon commented Jan 21, 2016

@dlwalsh, result is created inside the mapValues function and passed to reduce as initial value (also called an accumulator). Because it’s created inside mapValues, it can be mutated and mapValues would still be a pure function.

@dtinth

This comment has been minimized.

Show comment
Hide comment
@dtinth

dtinth May 4, 2016

@dlwalsh It’s algorithmic complexity. The “purer” version is O(n2) where the original version is O(n), so it’s not the same as using for loops vs Array#reduce. Here’s a benchmark:

function mapValues1(obj, fn) {
  return Object.keys(obj).reduce((result, key) => {
    result[key] = fn(obj[key], key);
    return result;
  }, {});
}

function mapValues2(obj, fn) {
  return Object.keys(obj).reduce((result, key) => (
    Object.assign({}, result, {
      [key]: fn(obj[key], key)
    })
  ), {});
}

var obj = { }
for (var i = 0; i < 10000; i ++) obj[i] = i

var mapper = x => x * x

console.time('mapValues1')
var result1 = mapValues1(obj, mapper)
console.timeEnd('mapValues1')

console.time('mapValues2')
var result2 = mapValues2(obj, mapper)
console.timeEnd('mapValues2')

// Ensure result is correct :)
require('assert').equal(result1[100], 10000)
require('assert').deepEqual(result1, result2)

Result:

mapValues1: 7.764ms
mapValues2: 10896.908ms

You can see that it takes 10 seconds to map a 10000-key object if you create a new object every time. Both functions are equally pure as @CrocoDillon said, since all the mutations happen inside the function.

dtinth commented May 4, 2016

@dlwalsh It’s algorithmic complexity. The “purer” version is O(n2) where the original version is O(n), so it’s not the same as using for loops vs Array#reduce. Here’s a benchmark:

function mapValues1(obj, fn) {
  return Object.keys(obj).reduce((result, key) => {
    result[key] = fn(obj[key], key);
    return result;
  }, {});
}

function mapValues2(obj, fn) {
  return Object.keys(obj).reduce((result, key) => (
    Object.assign({}, result, {
      [key]: fn(obj[key], key)
    })
  ), {});
}

var obj = { }
for (var i = 0; i < 10000; i ++) obj[i] = i

var mapper = x => x * x

console.time('mapValues1')
var result1 = mapValues1(obj, mapper)
console.timeEnd('mapValues1')

console.time('mapValues2')
var result2 = mapValues2(obj, mapper)
console.timeEnd('mapValues2')

// Ensure result is correct :)
require('assert').equal(result1[100], 10000)
require('assert').deepEqual(result1, result2)

Result:

mapValues1: 7.764ms
mapValues2: 10896.908ms

You can see that it takes 10 seconds to map a 10000-key object if you create a new object every time. Both functions are equally pure as @CrocoDillon said, since all the mutations happen inside the function.

@davesnx

This comment has been minimized.

Show comment
Hide comment
@davesnx

davesnx May 4, 2016

Well tested @dtinth, but it's basically the Object.assign creates a new object(with result and matches the key) each iteration, and the mapValues1 just add as a key in the resultant object.

davesnx commented May 4, 2016

Well tested @dtinth, but it's basically the Object.assign creates a new object(with result and matches the key) each iteration, and the mapValues1 just add as a key in the resultant object.

@vasanthk

This comment has been minimized.

Show comment
Hide comment
@vasanthk

vasanthk May 10, 2016

Pure Genius!

vasanthk commented May 10, 2016

Pure Genius!

@LucaColonnello

This comment has been minimized.

Show comment
Hide comment
@LucaColonnello

LucaColonnello May 22, 2016

I did the same for my Redux Course to explain how really Redux works and what is the concept. I notice that in a lot of courses about Redux, teachers miss the importance of selectors...

LucaColonnello commented May 22, 2016

I did the same for my Redux Course to explain how really Redux works and what is the concept. I notice that in a lot of courses about Redux, teachers miss the importance of selectors...

@tonytangau

This comment has been minimized.

Show comment
Hide comment
@tonytangau

tonytangau commented Jun 27, 2016

Artistic

@ansonkao

This comment has been minimized.

Show comment
Hide comment
@ansonkao

ansonkao Aug 21, 2016

It's possible to slim it down even further by removing the isDispatching checks! Then it would be < 90 lines!

ansonkao commented Aug 21, 2016

It's possible to slim it down even further by removing the isDispatching checks! Then it would be < 90 lines!

@sabha

This comment has been minimized.

Show comment
Hide comment
@sabha

sabha Oct 24, 2016

Thanks Dan. Do we have similar one for React-Redux. Trying to understand the connect method for adding features like "Resolve data before mounting the container".

sabha commented Oct 24, 2016

Thanks Dan. Do we have similar one for React-Redux. Trying to understand the connect method for adding features like "Resolve data before mounting the container".

@jakl

This comment has been minimized.

Show comment
Hide comment
@jakl

jakl Dec 13, 2016

I would love to watch a youtube video going over in detail every line of this code.

jakl commented Dec 13, 2016

I would love to watch a youtube video going over in detail every line of this code.

@thangchung

This comment has been minimized.

Show comment
Hide comment
@thangchung

thangchung Jan 20, 2017

Awesome. Simple but not simpler 👍

thangchung commented Jan 20, 2017

Awesome. Simple but not simpler 👍

@ehzawad

This comment has been minimized.

Show comment
Hide comment
@ehzawad

ehzawad commented Feb 24, 2017

Cool

@wayofthefuture

This comment has been minimized.

Show comment
Hide comment
@wayofthefuture

wayofthefuture Mar 21, 2017

Haters don't hate you know it's genius... #imnotworthy#

wayofthefuture commented Mar 21, 2017

Haters don't hate you know it's genius... #imnotworthy#

@ptim

This comment has been minimized.

Show comment
Hide comment
@ptim

ptim Jun 11, 2017

@sabha you probably found it already, but for those who com after, here is connect explained: https://gist.github.com/gaearon/1d19088790e70ac32ea636c025ba424e

ptim commented Jun 11, 2017

@sabha you probably found it already, but for those who com after, here is connect explained: https://gist.github.com/gaearon/1d19088790e70ac32ea636c025ba424e

@gandhirahul

This comment has been minimized.

Show comment
Hide comment
@gandhirahul

gandhirahul Oct 15, 2017

Amazingly beautiful code 👍

gandhirahul commented Oct 15, 2017

Amazingly beautiful code 👍

@LorisBachert

This comment has been minimized.

Show comment
Hide comment
@LorisBachert

LorisBachert Nov 2, 2017

I'm heavily breathing right now. This is just pure awesomeness!

LorisBachert commented Nov 2, 2017

I'm heavily breathing right now. This is just pure awesomeness!

@Shawnxkwang

This comment has been minimized.

Show comment
Hide comment
@Shawnxkwang

Shawnxkwang Aug 16, 2018

It's 2018. Is it too late for me to say 'cool'?

Shawnxkwang commented Aug 16, 2018

It's 2018. Is it too late for me to say 'cool'?

@ryuhangyeong

This comment has been minimized.

Show comment
Hide comment
@ryuhangyeong

ryuhangyeong commented Oct 14, 2018

Wow!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment