Skip to content

Instantly share code, notes, and snippets.

@rm-rf-etc
Last active July 11, 2019 21:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rm-rf-etc/7c6686252f15d939238158759e4f818a to your computer and use it in GitHub Desktop.
Save rm-rf-etc/7c6686252f15d939238158759e4f818a to your computer and use it in GitHub Desktop.
The Thunk Emperor Has No Clothes
/******************************\
The Thunk Emperor Has No Clothes
\******************************/
/* ACT ONE
myAction:
"I'm an action creator!"
*/
const myAction = () => ({
type: 'MY_ACTION',
});
/*
myThunkAction:
"And I am an ASYNCHRONOUS action creator!!"
*/
const asyncStuff = () => {};
const myThunkAction = () => async (dispatch) => {
await dispatch(asyncStuff());
dispatch(myAction());
};
/*
myAction:
"Oh, so you think you're all that, huh?"
*/
/* ACT TWO
myAction:
"No you're not, you're an imposter! You're nothing more
than a regular action creator."
myThunkAction:
"Gasp! How dare you?! Of course I'm not! I'm able to
invoke dispatch, `await` for asynchronous responses,
and `getState` so I can do intelligent stuff!! Hahaha,
you boring, stupid old synchronous action creator, you
can't do any of that, now can you?"
myAction:
"YES I can! I'll show, you pompous errogant asynchronous
action creator."
*/
import { dispatch, getState } from './store';
const myAction2 = async () => {
const state = getState();
await dispatch(asyncStuff(state.thing));
dispatch(myAction());
};
/* ACT THREE
myThunkAction:
"😱😱😱😱😱 You heathen! You're not allowed to do that!
The high priest hath forbidden you from importing the store!
Only _I_ am allowed to call `getState` and `dispatch`,
for they have been handed down to me by royal decree, and
by the very gods themselves, the supreme gods of Middleware!!"
myAction:
"Yo, check it, yo gods aint shit, you just a punk-ass bitch.
Instead of importing the store directly, you found a reference
to it using a dirty trick, you just slipped a 'middleware'
function to the user, knowing they wouldn't read it. You're
just a liar, and a tool."
*/
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
// see, it's ^ right ^ here!
if (typeof action === 'function') {
// and then, you just pass it to yourself,
// right here v!
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
/* ACT FOUR
myAction:
"There's nothing special about you, asynchronous action
creator. Nobody needs you. And your function signiture
is fucking confusing. I can pass you into `dispatch`,
or I can pass `dispatch` into YOU! Either way works
just fine, so what's the fucking point?"
myThunkAction:
"The point is to allow users to pass functions to
`dispatch` instead of objects, so that it still LOOKS
like they're using synchronous action creators, even
though they aren't. Obviously, that is VERY important."
myAction:
"If that's the goal, then why not just use a normal
action creator, and IMPORT THE STORE?"
myThunkAction:
"... BECAUSE GAERON SAID SO!! And he wrote the library,
so you're not allowed to think about this anymore!!
Besides, the thunk middleware is so simple, it's so
elllleeegaannnnt. Why would you not use it?"
myAction:
"That's not a reason. If I thought my framework
should be simple, I'd use jQuery."
*mic drop*
*/
// The example above is __not__ meant to show you
// a better alternative to redux-thunk, but simply
// that the premise for the value of using
// redux-thunk is wrong.
// Redux Thunk is a detrimental approach. While
// the library is incredibly small, that doesn't
// necessitate the quality of being a GOOD -- or
// even legitimate -- solution to your architectural
// concerns. React itself is not simple, but it's
// popular because it's GOOD, the premise is
// logical, and the solutions are real.
// If you need an alternative to redux-thunk, you
// probably need a FRAMEWORK FOR YOUR APPLICATION
// LOGIC. Recall that React is only designed to
// handle view rendering and user interaction. It
// *is* a framework, but it's only a framework for
// the VIEW (because updating the DOM efficiently
// and keeping it consistent with state is hard).
// Redux is actually not a framework for handling
// application logic. We were told that your app
// logic should go inside of asynchronous action
// creators, and not inside of synchronous action
// creators, but we now know that there is no real
// difference between these two things, only a thin
// facade to maintain the illusion of differnce.
// What you are missing is A FRAMEWORK FOR YOUR
// APPLICATION LOGIC! Thankfully, such a thing
// exists!
// REDUX-LOGIC !
// https://github.com/jeffbski/redux-logic
// Introduction:
// https://medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1
// Also, sagas and oberservables are not frameworks,
// they are utility libraries. They will not help
// your team adhere to a pre-defined structure.
// And they're also a lot harder to learn, and
// don't provide any upside over redux-logic.
// Make the smart decision, use redux-logic,
// for your own sake, and for the sake of your
// teammates.
// Happy coding.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment