redux-thunk
Advanced tools
Comparing version 2.3.0 to 2.4.2
@@ -1,91 +0,41 @@ | ||
(function webpackUniversalModuleDefinition(root, factory) { | ||
if(typeof exports === 'object' && typeof module === 'object') | ||
module.exports = factory(); | ||
else if(typeof define === 'function' && define.amd) | ||
define([], factory); | ||
else if(typeof exports === 'object') | ||
exports["ReduxThunk"] = factory(); | ||
else | ||
root["ReduxThunk"] = factory(); | ||
})(this, function() { | ||
return /******/ (function(modules) { // webpackBootstrap | ||
/******/ // The module cache | ||
/******/ var installedModules = {}; | ||
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ReduxThunk = factory()); | ||
})(this, (function () { 'use strict'; | ||
/******/ // The require function | ||
/******/ function __webpack_require__(moduleId) { | ||
/** A function that accepts a potential "extra argument" value to be injected later, | ||
* and returns an instance of the thunk middleware that uses that value | ||
*/ | ||
function createThunkMiddleware(extraArgument) { | ||
// Standard Redux middleware definition pattern: | ||
// See: https://redux.js.org/tutorials/fundamentals/part-4-store#writing-custom-middleware | ||
var middleware = function middleware(_ref) { | ||
var dispatch = _ref.dispatch, | ||
getState = _ref.getState; | ||
return function (next) { | ||
return function (action) { | ||
// The thunk middleware looks for any functions that were passed to `store.dispatch`. | ||
// If this "action" is really a function, call it and return the result. | ||
if (typeof action === 'function') { | ||
// Inject the store's `dispatch` and `getState` methods, as well as any "extra arg" | ||
return action(dispatch, getState, extraArgument); | ||
} // Otherwise, pass the action down the middleware chain as usual | ||
/******/ // Check if module is in cache | ||
/******/ if(installedModules[moduleId]) | ||
/******/ return installedModules[moduleId].exports; | ||
/******/ // Create a new module (and put it into the cache) | ||
/******/ var module = installedModules[moduleId] = { | ||
/******/ exports: {}, | ||
/******/ id: moduleId, | ||
/******/ loaded: false | ||
/******/ }; | ||
return next(action); | ||
}; | ||
}; | ||
}; | ||
/******/ // Execute the module function | ||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); | ||
return middleware; | ||
} | ||
/******/ // Flag the module as loaded | ||
/******/ module.loaded = true; | ||
var thunk = createThunkMiddleware(); // Attach the factory function so users can create a customized version | ||
// with whatever "extra arg" they want to inject into their thunks | ||
/******/ // Return the exports of the module | ||
/******/ return module.exports; | ||
/******/ } | ||
thunk.withExtraArgument = createThunkMiddleware; | ||
return thunk; | ||
/******/ // expose the modules object (__webpack_modules__) | ||
/******/ __webpack_require__.m = modules; | ||
/******/ // expose the module cache | ||
/******/ __webpack_require__.c = installedModules; | ||
/******/ // __webpack_public_path__ | ||
/******/ __webpack_require__.p = ""; | ||
/******/ // Load entry module and return exports | ||
/******/ return __webpack_require__(0); | ||
/******/ }) | ||
/************************************************************************/ | ||
/******/ ([ | ||
/* 0 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
module.exports = __webpack_require__(1); | ||
/***/ }), | ||
/* 1 */ | ||
/***/ (function(module, exports) { | ||
'use strict'; | ||
exports.__esModule = true; | ||
function createThunkMiddleware(extraArgument) { | ||
return function (_ref) { | ||
var dispatch = _ref.dispatch, | ||
getState = _ref.getState; | ||
return function (next) { | ||
return function (action) { | ||
if (typeof action === 'function') { | ||
return action(dispatch, getState, extraArgument); | ||
} | ||
return next(action); | ||
}; | ||
}; | ||
}; | ||
} | ||
var thunk = createThunkMiddleware(); | ||
thunk.withExtraArgument = createThunkMiddleware; | ||
exports['default'] = thunk; | ||
/***/ }) | ||
/******/ ]) | ||
}); | ||
; | ||
})); |
@@ -1,1 +0,1 @@ | ||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ReduxThunk=e():t.ReduxThunk=e()}(this,function(){return function(t){function e(o){if(n[o])return n[o].exports;var r=n[o]={exports:{},id:o,loaded:!1};return t[o].call(r.exports,r,r.exports,e),r.loaded=!0,r.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){t.exports=n(1)},function(t,e){"use strict";function n(t){return function(e){var n=e.dispatch,o=e.getState;return function(e){return function(r){return"function"==typeof r?r(n,o,t):e(r)}}}}e.__esModule=!0;var o=n();o.withExtraArgument=n,e.default=o}])}); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).ReduxThunk=t()}(this,(function(){"use strict";function e(e){return function(t){var n=t.dispatch,u=t.getState;return function(t){return function(o){return"function"==typeof o?o(n,u,e):t(o)}}}}var t=e();return t.withExtraArgument=e,t})); |
@@ -0,3 +1,8 @@ | ||
/** A function that accepts a potential "extra argument" value to be injected later, | ||
* and returns an instance of the thunk middleware that uses that value | ||
*/ | ||
function createThunkMiddleware(extraArgument) { | ||
return function (_ref) { | ||
// Standard Redux middleware definition pattern: | ||
// See: https://redux.js.org/tutorials/fundamentals/part-4-store#writing-custom-middleware | ||
var middleware = function middleware(_ref) { | ||
var dispatch = _ref.dispatch, | ||
@@ -7,6 +12,10 @@ getState = _ref.getState; | ||
return function (action) { | ||
// The thunk middleware looks for any functions that were passed to `store.dispatch`. | ||
// If this "action" is really a function, call it and return the result. | ||
if (typeof action === 'function') { | ||
// Inject the store's `dispatch` and `getState` methods, as well as any "extra arg" | ||
return action(dispatch, getState, extraArgument); | ||
} | ||
} // Otherwise, pass the action down the middleware chain as usual | ||
return next(action); | ||
@@ -16,7 +25,10 @@ }; | ||
}; | ||
return middleware; | ||
} | ||
var thunk = createThunkMiddleware(); | ||
var thunk = createThunkMiddleware(); // Attach the factory function so users can create a customized version | ||
// with whatever "extra arg" they want to inject into their thunks | ||
thunk.withExtraArgument = createThunkMiddleware; | ||
export default thunk; |
@@ -1,6 +0,15 @@ | ||
'use strict'; | ||
"use strict"; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.default = void 0; | ||
/** A function that accepts a potential "extra argument" value to be injected later, | ||
* and returns an instance of the thunk middleware that uses that value | ||
*/ | ||
function createThunkMiddleware(extraArgument) { | ||
return function (_ref) { | ||
// Standard Redux middleware definition pattern: | ||
// See: https://redux.js.org/tutorials/fundamentals/part-4-store#writing-custom-middleware | ||
var middleware = function middleware(_ref) { | ||
var dispatch = _ref.dispatch, | ||
@@ -10,6 +19,10 @@ getState = _ref.getState; | ||
return function (action) { | ||
// The thunk middleware looks for any functions that were passed to `store.dispatch`. | ||
// If this "action" is really a function, call it and return the result. | ||
if (typeof action === 'function') { | ||
// Inject the store's `dispatch` and `getState` methods, as well as any "extra arg" | ||
return action(dispatch, getState, extraArgument); | ||
} | ||
} // Otherwise, pass the action down the middleware chain as usual | ||
return next(action); | ||
@@ -19,7 +32,11 @@ }; | ||
}; | ||
return middleware; | ||
} | ||
var thunk = createThunkMiddleware(); | ||
var thunk = createThunkMiddleware(); // Attach the factory function so users can create a customized version | ||
// with whatever "extra arg" they want to inject into their thunks | ||
thunk.withExtraArgument = createThunkMiddleware; | ||
exports['default'] = thunk; | ||
var _default = thunk; | ||
exports.default = _default; |
@@ -0,0 +0,0 @@ The MIT License (MIT) |
{ | ||
"name": "redux-thunk", | ||
"version": "2.3.0", | ||
"version": "2.4.2", | ||
"license": "MIT", | ||
@@ -19,3 +19,4 @@ "description": "Thunk middleware for Redux.", | ||
"module": "es/index.js", | ||
"typings": "./index.d.ts", | ||
"types": "es/index.d.ts", | ||
"sideEffects": false, | ||
"files": [ | ||
@@ -26,52 +27,52 @@ "lib", | ||
"dist", | ||
"index.d.ts" | ||
"extend-redux.d.ts" | ||
], | ||
"scripts": { | ||
"clean": "rimraf lib dist es", | ||
"prepare": "npm run clean && npm run lint && npm run test && npm run build", | ||
"lint": "eslint src test", | ||
"test": "cross-env BABEL_ENV=commonjs mocha --compilers js:babel-core/register --reporter spec test/*.js", | ||
"build": "npm run build:commonjs && npm run build:umd && npm run build:umd:min && npm run build:es", | ||
"build:commonjs": "cross-env BABEL_ENV=commonjs babel src --out-dir lib", | ||
"build:es": "cross-env BABEL_ENV=es babel src --out-dir es", | ||
"build:umd": "cross-env BABEL_ENV=commonjs NODE_ENV=development webpack", | ||
"build:umd:min": "cross-env BABEL_ENV=commonjs NODE_ENV=production webpack" | ||
"prepublishOnly": "npm run clean && npm run lint && npm run test && npm run build", | ||
"format": "prettier --write {src,test,typescript_test}/**/*.{js,ts}", | ||
"format:check": "prettier --check {src,test,typescript_test}/**/*.{js,ts}", | ||
"lint": "eslint {src,test,typescript_test}/**/*.{js,ts}", | ||
"test": "jest", | ||
"test:cov": "jest --coverage", | ||
"test:typescript": "npm run test:typescript:main && npm run test:typescript:extended", | ||
"test:typescript:main": "tsc --noEmit -p typescript_test/tsconfig.json", | ||
"test:typescript:extended": "tsc --noEmit -p typescript_test/typescript_extended/tsconfig.json", | ||
"build:commonjs": "cross-env BABEL_ENV=commonjs babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir lib ", | ||
"build:es": "babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir es", | ||
"build:umd": "cross-env NODE_ENV=development rollup -c -o dist/redux-thunk.js", | ||
"build:umd:min": "cross-env NODE_ENV=production rollup -c -o dist/redux-thunk.min.js", | ||
"build:types": "tsc", | ||
"build": "rimraf dist lib es && npm run build:types && npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min", | ||
"api-types": "api-extractor run --local" | ||
}, | ||
"peerDependencies": { | ||
"redux": "^4" | ||
}, | ||
"devDependencies": { | ||
"babel-cli": "^6.6.5", | ||
"babel-core": "^6.6.5", | ||
"babel-eslint": "^5.0.0-beta4", | ||
"babel-loader": "^6.2.4", | ||
"babel-plugin-check-es2015-constants": "^6.6.5", | ||
"babel-plugin-transform-es2015-arrow-functions": "^6.5.2", | ||
"babel-plugin-transform-es2015-block-scoped-functions": "^6.6.5", | ||
"babel-plugin-transform-es2015-block-scoping": "^6.6.5", | ||
"babel-plugin-transform-es2015-classes": "^6.6.5", | ||
"babel-plugin-transform-es2015-computed-properties": "^6.6.5", | ||
"babel-plugin-transform-es2015-destructuring": "^6.6.5", | ||
"babel-plugin-transform-es2015-for-of": "^6.6.0", | ||
"babel-plugin-transform-es2015-function-name": "^6.5.0", | ||
"babel-plugin-transform-es2015-literals": "^6.5.0", | ||
"babel-plugin-transform-es2015-modules-commonjs": "^6.6.5", | ||
"babel-plugin-transform-es2015-object-super": "^6.6.5", | ||
"babel-plugin-transform-es2015-parameters": "^6.6.5", | ||
"babel-plugin-transform-es2015-shorthand-properties": "^6.5.0", | ||
"babel-plugin-transform-es2015-spread": "^6.6.5", | ||
"babel-plugin-transform-es2015-sticky-regex": "^6.5.0", | ||
"babel-plugin-transform-es2015-template-literals": "^6.6.5", | ||
"babel-plugin-transform-es2015-unicode-regex": "^6.5.0", | ||
"babel-plugin-transform-es3-member-expression-literals": "^6.5.0", | ||
"babel-plugin-transform-es3-property-literals": "^6.5.0", | ||
"chai": "^3.2.0", | ||
"cross-env": "^1.0.7", | ||
"eslint": "^1.10.2", | ||
"eslint-config-airbnb": "1.0.2", | ||
"eslint-plugin-react": "^4.1.0", | ||
"mocha": "^2.2.5", | ||
"redux": "~4.0.0", | ||
"rimraf": "^2.5.2", | ||
"typescript": "~2.6.2", | ||
"typings-tester": "^0.3.1", | ||
"webpack": "^1.12.14" | ||
"@babel/cli": "^7.15.7", | ||
"@babel/core": "^7.15.8", | ||
"@babel/preset-env": "^7.15.8", | ||
"@babel/preset-typescript": "^7.15.0", | ||
"@babel/register": "^7.15.3", | ||
"@microsoft/api-extractor": "^7.18.16", | ||
"@rollup/plugin-babel": "^5.3.0", | ||
"@rollup/plugin-commonjs": "^21.0.1", | ||
"@rollup/plugin-node-resolve": "^13.0.6", | ||
"@rollup/plugin-replace": "^3.0.0", | ||
"@types/jest": "^27.0.2", | ||
"@typescript-eslint/eslint-plugin": "^5.1.0", | ||
"@typescript-eslint/parser": "^5.1.0", | ||
"cross-env": "^7.0.3", | ||
"eslint": "^7.32.0", | ||
"eslint-config-prettier": "^8.3.0", | ||
"jest": "^27.3.1", | ||
"prettier": "^2.4.1", | ||
"redux": "^4", | ||
"rimraf": "^3.0.2", | ||
"rollup": "^2.58.1", | ||
"rollup-plugin-terser": "^7.0.2", | ||
"ts-jest": "27.0.7", | ||
"typescript": "^4.4" | ||
} | ||
} |
387
README.md
@@ -1,47 +0,195 @@ | ||
Redux Thunk | ||
============= | ||
# Redux Thunk | ||
Thunk [middleware](https://redux.js.org/advanced/middleware) for Redux. | ||
Thunk [middleware](https://redux.js.org/tutorials/fundamentals/part-4-store#middleware) for Redux. It allows writing functions with logic inside that can interact with a Redux store's `dispatch` and `getState` methods. | ||
[![build status](https://img.shields.io/travis/reduxjs/redux-thunk/master.svg?style=flat-square)](https://travis-ci.org/reduxjs/redux-thunk) | ||
For complete usage instructions and useful patterns, see the [Redux docs **Writing Logic with Thunks** page](https://redux.js.org/usage/writing-logic-thunks). | ||
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/reduxjs/redux-thunk/Tests) | ||
[![npm version](https://img.shields.io/npm/v/redux-thunk.svg?style=flat-square)](https://www.npmjs.com/package/redux-thunk) | ||
[![npm downloads](https://img.shields.io/npm/dm/redux-thunk.svg?style=flat-square)](https://www.npmjs.com/package/redux-thunk) | ||
## Installation and Setup | ||
### Redux Toolkit | ||
If you're using [our official Redux Toolkit package](https://redux-toolkit.js.org) as recommended, there's nothing to install - RTK's `configureStore` API already adds the thunk middleware by default: | ||
```js | ||
npm install --save redux-thunk | ||
import { configureStore } from '@reduxjs/toolkit' | ||
import todosReducer from './features/todos/todosSlice' | ||
import filtersReducer from './features/filters/filtersSlice' | ||
const store = configureStore({ | ||
reducer: { | ||
todos: todosReducer, | ||
filters: filtersReducer | ||
} | ||
}) | ||
// The thunk middleware was automatically added | ||
``` | ||
## Note on 2.x Update | ||
### Manual Setup | ||
Most tutorials today assume Redux Thunk 1.x so you might run into an issue when running their code with 2.x. | ||
**If you use Redux Thunk 2.x in CommonJS environment, [don’t forget to add `.default` to your import](https://github.com/reduxjs/redux-thunk/releases/tag/v2.0.0):** | ||
If you're using the basic Redux `createStore` API and need to set this up manually, first add the `redux-thunk` package: | ||
```sh | ||
npm install redux-thunk | ||
yarn add redux-thunk | ||
``` | ||
The thunk middleware is the default export. | ||
<details> | ||
<summary><b>More Details: Importing the thunk middleware</b></summary> | ||
If you're using ES modules: | ||
```js | ||
import thunk from 'redux-thunk' // no changes here 😀 | ||
``` | ||
If you use Redux Thunk 2.x in a CommonJS environment, | ||
[don’t forget to add `.default` to your import](https://github.com/reduxjs/redux-thunk/releases/tag/v2.0.0): | ||
```diff | ||
- var ReduxThunk = require('redux-thunk') | ||
+ var ReduxThunk = require('redux-thunk').default | ||
- const thunk = require('redux-thunk') | ||
+ const thunk = require('redux-thunk').default | ||
``` | ||
If you used ES modules, you’re already all good: | ||
Additionally, since 2.x, we also support a | ||
[UMD build](https://unpkg.com/redux-thunk/dist/redux-thunk.min.js) for use as a global script tag: | ||
```js | ||
import ReduxThunk from 'redux-thunk' // no changes here 😀 | ||
const ReduxThunk = window.ReduxThunk | ||
``` | ||
Additionally, since 2.x, we also support a [UMD build](https://unpkg.com/redux-thunk/dist/redux-thunk.min.js): | ||
</details> | ||
Then, to enable Redux Thunk, use | ||
[`applyMiddleware()`](https://redux.js.org/api/applymiddleware): | ||
```js | ||
var ReduxThunk = window.ReduxThunk.default | ||
import { createStore, applyMiddleware } from 'redux' | ||
import thunk from 'redux-thunk' | ||
import rootReducer from './reducers/index' | ||
const store = createStore(rootReducer, applyMiddleware(thunk)) | ||
``` | ||
As you can see, it also requires `.default` at the end. | ||
### Injecting a Custom Argument | ||
Since 2.1.0, Redux Thunk supports injecting a custom argument into the thunk middleware. This is typically useful for cases like using an API service layer that could be swapped out for a mock service in tests. | ||
For Redux Toolkit, the `getDefaultMiddleware` callback inside of `configureStore` lets you pass in a custom `extraArgument`: | ||
```js | ||
import { configureStore } from '@reduxjs/toolkit' | ||
import rootReducer from './reducer' | ||
import { myCustomApiService } from './api' | ||
const store = configureStore({ | ||
reducer: rootReducer, | ||
middleware: getDefaultMiddleware => | ||
getDefaultMiddleware({ | ||
thunk: { | ||
extraArgument: myCustomApiService | ||
} | ||
}) | ||
}) | ||
// later | ||
function fetchUser(id) { | ||
// The `extraArgument` is the third arg for thunk functions | ||
return (dispatch, getState, api) => { | ||
// you can use api here | ||
} | ||
} | ||
``` | ||
If you need to pass in multiple values, combine them into a single object: | ||
```js | ||
const store = configureStore({ | ||
reducer: rootReducer, | ||
middleware: getDefaultMiddleware => | ||
getDefaultMiddleware({ | ||
thunk: { | ||
extraArgument: { | ||
api: myCustomApiService, | ||
otherValue: 42 | ||
} | ||
} | ||
}) | ||
}) | ||
// later | ||
function fetchUser(id) { | ||
return (dispatch, getState, { api, otherValue }) => { | ||
// you can use api and something else here | ||
} | ||
} | ||
``` | ||
If you're setting up the store by hand, the default `thunk` export has an attached `thunk.withExtraArgument()` function that should be used to generate the correct thunk middleware: | ||
```js | ||
const store = createStore( | ||
reducer, | ||
applyMiddleware(thunk.withExtraArgument(api)) | ||
) | ||
``` | ||
## Why Do I Need This? | ||
If you’re not sure whether you need it, you probably don’t. | ||
With a plain basic Redux store, you can only do simple synchronous updates by | ||
dispatching an action. Middleware extends the store's abilities, and lets you | ||
write async logic that interacts with the store. | ||
**[Read this for an in-depth introduction to thunks in Redux.](http://stackoverflow.com/questions/35411423/how-to-dispatch-a-redux-action-with-a-timeout/35415559#35415559)** | ||
Thunks are the recommended middleware for basic Redux side effects logic, | ||
including complex synchronous logic that needs access to the store, and simple | ||
async logic like AJAX requests. | ||
For more details on why thunks are useful, see: | ||
- **Redux docs: Writing Logic with Thunks** | ||
https://redux.js.org/usage/writing-logic-thunks | ||
The official usage guide page on thunks. Covers why they exist, how the thunk middleware works, and useful patterns for using thunks. | ||
- **Stack Overflow: Dispatching Redux Actions with a Timeout** | ||
http://stackoverflow.com/questions/35411423/how-to-dispatch-a-redux-action-with-a-timeout/35415559#35415559 | ||
Dan Abramov explains the basics of managing async behavior in Redux, walking | ||
through a progressive series of approaches (inline async calls, async action | ||
creators, thunk middleware). | ||
- **Stack Overflow: Why do we need middleware for async flow in Redux?** | ||
http://stackoverflow.com/questions/34570758/why-do-we-need-middleware-for-async-flow-in-redux/34599594#34599594 | ||
Dan Abramov gives reasons for using thunks and async middleware, and some | ||
useful patterns for using thunks. | ||
- **What the heck is a "thunk"?** | ||
https://daveceddia.com/what-is-a-thunk/ | ||
A quick explanation for what the word "thunk" means in general, and for Redux | ||
specifically. | ||
- **Thunks in Redux: The Basics** | ||
https://medium.com/fullstack-academy/thunks-in-redux-the-basics-85e538a3fe60 | ||
A detailed look at what thunks are, what they solve, and how to use them. | ||
You may also want to read the | ||
**[Redux FAQ entry on choosing which async middleware to use](https://redux.js.org/faq/actions#what-async-middleware-should-i-use-how-do-you-decide-between-thunks-sagas-observables-or-something-else)**. | ||
While the thunk middleware is not directly included with the Redux core library, | ||
it is used by default in our | ||
**[`@reduxjs/toolkit` package](https://github.com/reduxjs/redux-toolkit)**. | ||
## Motivation | ||
Redux Thunk [middleware](https://github.com/reactjs/redux/blob/master/docs/advanced/Middleware.md) allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods `dispatch` and `getState` as parameters. | ||
Redux Thunk [middleware](https://redux.js.org/tutorials/fundamentals/part-4-store#middleware) | ||
allows you to write action creators that return a function instead of an action. | ||
The thunk can be used to delay the dispatch of an action, or to dispatch only if | ||
a certain condition is met. The inner function receives the store methods | ||
`dispatch` and `getState` as parameters. | ||
@@ -51,3 +199,3 @@ An action creator that returns a function to perform asynchronous dispatch: | ||
```js | ||
const INCREMENT_COUNTER = 'INCREMENT_COUNTER'; | ||
const INCREMENT_COUNTER = 'INCREMENT_COUNTER' | ||
@@ -57,3 +205,3 @@ function increment() { | ||
type: INCREMENT_COUNTER | ||
}; | ||
} | ||
} | ||
@@ -65,5 +213,5 @@ | ||
// Yay! Can invoke sync or async actions with `dispatch` | ||
dispatch(increment()); | ||
}, 1000); | ||
}; | ||
dispatch(increment()) | ||
}, 1000) | ||
} | ||
} | ||
@@ -77,10 +225,10 @@ ``` | ||
return (dispatch, getState) => { | ||
const { counter } = getState(); | ||
const { counter } = getState() | ||
if (counter % 2 === 0) { | ||
return; | ||
return | ||
} | ||
dispatch(increment()); | ||
}; | ||
dispatch(increment()) | ||
} | ||
} | ||
@@ -91,3 +239,4 @@ ``` | ||
A [thunk](https://en.wikipedia.org/wiki/Thunk) is a function that wraps an expression to delay its evaluation. | ||
A [thunk](https://en.wikipedia.org/wiki/Thunk) is a function that wraps an | ||
expression to delay its evaluation. | ||
@@ -97,3 +246,3 @@ ```js | ||
// x === 3 | ||
let x = 1 + 2; | ||
let x = 1 + 2 | ||
@@ -103,44 +252,25 @@ // calculation of 1 + 2 is delayed | ||
// foo is a thunk! | ||
let foo = () => 1 + 2; | ||
let foo = () => 1 + 2 | ||
``` | ||
The term [originated](https://en.wikipedia.org/wiki/Thunk#cite_note-1) as a humorous past-tense version of "think". | ||
The term [originated](https://en.wikipedia.org/wiki/Thunk#cite_note-1) as a | ||
humorous past-tense version of "think". | ||
## Installation | ||
``` | ||
npm install --save redux-thunk | ||
``` | ||
Then, to enable Redux Thunk, use [`applyMiddleware()`](https://redux.js.org/api-reference/applymiddleware): | ||
```js | ||
import { createStore, applyMiddleware } from 'redux'; | ||
import thunk from 'redux-thunk'; | ||
import rootReducer from './reducers/index'; | ||
// Note: this API requires redux@>=3.1.0 | ||
const store = createStore( | ||
rootReducer, | ||
applyMiddleware(thunk) | ||
); | ||
``` | ||
## Composition | ||
Any return value from the inner function will be available as the return value of `dispatch` itself. This is convenient for orchestrating an asynchronous control flow with thunk action creators dispatching each other and returning Promises to wait for each other’s completion: | ||
Any return value from the inner function will be available as the return value | ||
of `dispatch` itself. This is convenient for orchestrating an asynchronous | ||
control flow with thunk action creators dispatching each other and returning | ||
Promises to wait for each other’s completion: | ||
```js | ||
import { createStore, applyMiddleware } from 'redux'; | ||
import thunk from 'redux-thunk'; | ||
import rootReducer from './reducers'; | ||
import { createStore, applyMiddleware } from 'redux' | ||
import thunk from 'redux-thunk' | ||
import rootReducer from './reducers' | ||
// Note: this API requires redux@>=3.1.0 | ||
const store = createStore( | ||
rootReducer, | ||
applyMiddleware(thunk) | ||
); | ||
const store = createStore(rootReducer, applyMiddleware(thunk)) | ||
function fetchSecretSauce() { | ||
return fetch('https://www.google.com/search?q=secret+sauce'); | ||
return fetch('https://www.google.com/search?q=secret+sauce') | ||
} | ||
@@ -157,3 +287,3 @@ | ||
secretSauce | ||
}; | ||
} | ||
} | ||
@@ -167,3 +297,3 @@ | ||
error | ||
}; | ||
} | ||
} | ||
@@ -175,7 +305,7 @@ | ||
amount | ||
}; | ||
} | ||
} | ||
// Even without middleware, you can dispatch an action: | ||
store.dispatch(withdrawMoney(100)); | ||
store.dispatch(withdrawMoney(100)) | ||
@@ -186,11 +316,10 @@ // But what do you do when you need to start an asynchronous action, | ||
// Meet thunks. | ||
// A thunk is a function that returns a function. | ||
// This is a thunk. | ||
// A thunk in this context is a function that can be dispatched to perform async | ||
// activity and can dispatch actions and read state. | ||
// This is an action creator that returns a thunk: | ||
function makeASandwichWithSecretSauce(forPerson) { | ||
// Invert control! | ||
// Return a function that accepts `dispatch` so we can dispatch later. | ||
// Thunk middleware knows how to turn thunk async actions into actions. | ||
// We can invert control here by returning a function - the "thunk". | ||
// When this function is passed to `dispatch`, the thunk middleware will intercept it, | ||
// and call it with `dispatch` and `getState` as arguments. | ||
// This gives the thunk function the ability to run some logic, and still interact with the store. | ||
return function (dispatch) { | ||
@@ -200,4 +329,4 @@ return fetchSecretSauce().then( | ||
error => dispatch(apologize('The Sandwich Shop', forPerson, error)) | ||
); | ||
}; | ||
) | ||
} | ||
} | ||
@@ -208,5 +337,3 @@ | ||
store.dispatch( | ||
makeASandwichWithSecretSauce('Me') | ||
); | ||
store.dispatch(makeASandwichWithSecretSauce('Me')) | ||
@@ -216,7 +343,5 @@ // It even takes care to return the thunk’s return value | ||
store.dispatch( | ||
makeASandwichWithSecretSauce('My wife') | ||
).then(() => { | ||
console.log('Done!'); | ||
}); | ||
store.dispatch(makeASandwichWithSecretSauce('My partner')).then(() => { | ||
console.log('Done!') | ||
}) | ||
@@ -230,7 +355,6 @@ // In fact I can write action creators that dispatch | ||
if (!getState().sandwiches.isShopOpen) { | ||
// You don’t have to return Promises, but it’s a handy convention | ||
// so the caller can always call .then() on async dispatch result. | ||
return Promise.resolve(); | ||
return Promise.resolve() | ||
} | ||
@@ -241,18 +365,18 @@ | ||
return dispatch( | ||
makeASandwichWithSecretSauce('My Grandma') | ||
).then(() => | ||
Promise.all([ | ||
dispatch(makeASandwichWithSecretSauce('Me')), | ||
dispatch(makeASandwichWithSecretSauce('My wife')) | ||
]) | ||
).then(() => | ||
dispatch(makeASandwichWithSecretSauce('Our kids')) | ||
).then(() => | ||
dispatch(getState().myMoney > 42 ? | ||
withdrawMoney(42) : | ||
apologize('Me', 'The Sandwich Shop') | ||
return dispatch(makeASandwichWithSecretSauce('My Grandma')) | ||
.then(() => | ||
Promise.all([ | ||
dispatch(makeASandwichWithSecretSauce('Me')), | ||
dispatch(makeASandwichWithSecretSauce('My wife')) | ||
]) | ||
) | ||
); | ||
}; | ||
.then(() => dispatch(makeASandwichWithSecretSauce('Our kids'))) | ||
.then(() => | ||
dispatch( | ||
getState().myMoney > 42 | ||
? withdrawMoney(42) | ||
: apologize('Me', 'The Sandwich Shop') | ||
) | ||
) | ||
} | ||
} | ||
@@ -263,7 +387,7 @@ | ||
store.dispatch( | ||
makeSandwichesForEverybody() | ||
).then(() => | ||
response.send(ReactDOMServer.renderToString(<MyApp store={store} />)) | ||
); | ||
store | ||
.dispatch(makeSandwichesForEverybody()) | ||
.then(() => | ||
response.send(ReactDOMServer.renderToString(<MyApp store={store} />)) | ||
) | ||
@@ -273,10 +397,8 @@ // I can also dispatch a thunk async action from a component | ||
import { connect } from 'react-redux'; | ||
import { Component } from 'react'; | ||
import { connect } from 'react-redux' | ||
import { Component } from 'react' | ||
class SandwichShop extends Component { | ||
componentDidMount() { | ||
this.props.dispatch( | ||
makeASandwichWithSecretSauce(this.props.forPerson) | ||
); | ||
this.props.dispatch(makeASandwichWithSecretSauce(this.props.forPerson)) | ||
} | ||
@@ -286,5 +408,3 @@ | ||
if (prevProps.forPerson !== this.props.forPerson) { | ||
this.props.dispatch( | ||
makeASandwichWithSecretSauce(this.props.forPerson) | ||
); | ||
this.props.dispatch(makeASandwichWithSecretSauce(this.props.forPerson)) | ||
} | ||
@@ -298,46 +418,9 @@ } | ||
export default connect( | ||
state => ({ | ||
sandwiches: state.sandwiches | ||
}) | ||
)(SandwichShop); | ||
export default connect(state => ({ | ||
sandwiches: state.sandwiches | ||
}))(SandwichShop) | ||
``` | ||
## Injecting a Custom Argument | ||
Since 2.1.0, Redux Thunk supports injecting a custom argument using the `withExtraArgument` function: | ||
```js | ||
const store = createStore( | ||
reducer, | ||
applyMiddleware(thunk.withExtraArgument(api)) | ||
) | ||
// later | ||
function fetchUser(id) { | ||
return (dispatch, getState, api) => { | ||
// you can use api here | ||
} | ||
} | ||
``` | ||
To pass multiple things, just wrap them in a single object and use destructuring: | ||
```js | ||
const store = createStore( | ||
reducer, | ||
applyMiddleware(thunk.withExtraArgument({ api, whatever })) | ||
) | ||
// later | ||
function fetchUser(id) { | ||
return (dispatch, getState, { api, whatever }) => { | ||
// you can use api and something else here | ||
} | ||
} | ||
``` | ||
## License | ||
MIT |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
32059
24
12
320
407
0
1