Last active
July 11, 2019 21:31
-
-
Save rm-rf-etc/7c6686252f15d939238158759e4f818a to your computer and use it in GitHub Desktop.
The Thunk Emperor Has No Clothes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************************\ | |
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