Gathering detailed insights and metrics for redux-thunk
Gathering detailed insights and metrics for redux-thunk
Gathering detailed insights and metrics for redux-thunk
Gathering detailed insights and metrics for redux-thunk
typescript-fsa-redux-thunk
TypeScript FSA utilities for redux-thunk
redux-thunk-actions
redux-thunk-actions ===================
ember-redux-thunk-shim
redux-thunk for Ember apps
redux-thunk-recursion-detect
A drop-in replacement for `redux-thunk` that allows middleware to detect that a thunk has been dispatched from within another thunk
npm install redux-thunk
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
17,776 Stars
232 Commits
1,043 Forks
170 Watching
3 Branches
59 Contributors
Updated on 27 Nov 2024
Minified
Minified + Gzipped
TypeScript (95.17%)
JavaScript (4.83%)
Cumulative downloads
Total Downloads
Last day
-2.6%
1,124,424
Compared to previous day
Last week
2.6%
5,841,949
Compared to previous week
Last month
11.9%
24,451,481
Compared to previous month
Last year
14.9%
263,244,049
Compared to previous year
1
Thunk middleware for Redux. It allows writing functions with logic inside that can interact with a Redux store's dispatch
and getState
methods.
For complete usage instructions and useful patterns, see the Redux docs Writing Logic with Thunks page.
If you're using our official Redux Toolkit package as recommended, there's nothing to install - RTK's configureStore
API already adds the thunk middleware by default:
1import { configureStore } from '@reduxjs/toolkit' 2 3import todosReducer from './features/todos/todosSlice' 4import filtersReducer from './features/filters/filtersSlice' 5 6const store = configureStore({ 7 reducer: { 8 todos: todosReducer, 9 filters: filtersReducer, 10 }, 11}) 12 13// The thunk middleware was automatically added
If you're using the basic Redux createStore
API and need to set this up manually, first add the redux-thunk
package:
1npm install redux-thunk 2 3yarn add redux-thunk
The thunk middleware is a named export.
If you're using ES modules:
1import { thunk } from 'redux-thunk'
If you use Redux Thunk in a CommonJS environment:
1const { thunk } = require('redux-thunk')
Then, to enable Redux Thunk, use
applyMiddleware()
:
1import { createStore, applyMiddleware } from 'redux' 2import { thunk } from 'redux-thunk' 3import rootReducer from './reducers/index' 4 5const store = createStore(rootReducer, applyMiddleware(thunk))
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
:
1import { configureStore } from '@reduxjs/toolkit' 2import rootReducer from './reducer' 3import { myCustomApiService } from './api' 4 5const store = configureStore({ 6 reducer: rootReducer, 7 middleware: getDefaultMiddleware => 8 getDefaultMiddleware({ 9 thunk: { 10 extraArgument: myCustomApiService, 11 }, 12 }), 13}) 14 15// later 16function fetchUser(id) { 17 // The `extraArgument` is the third arg for thunk functions 18 return (dispatch, getState, api) => { 19 // you can use api here 20 } 21}
If you need to pass in multiple values, combine them into a single object:
1const store = configureStore({
2 reducer: rootReducer,
3 middleware: getDefaultMiddleware =>
4 getDefaultMiddleware({
5 thunk: {
6 extraArgument: {
7 api: myCustomApiService,
8 otherValue: 42,
9 },
10 },
11 }),
12})
13
14// later
15function fetchUser(id) {
16 return (dispatch, getState, { api, otherValue }) => {
17 // you can use api and something else here
18 }
19}
If you're setting up the store by hand, the named export withExtraArgument()
function should be used to generate the correct thunk middleware:
1const store = createStore(reducer, applyMiddleware(withExtraArgument(api)))
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.
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.
While the thunk middleware is not directly included with the Redux core library,
it is used by default in our
@reduxjs/toolkit
package.
Redux Thunk 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.
An action creator that returns a function to perform asynchronous dispatch:
1const INCREMENT_COUNTER = 'INCREMENT_COUNTER' 2 3function increment() { 4 return { 5 type: INCREMENT_COUNTER, 6 } 7} 8 9function incrementAsync() { 10 return dispatch => { 11 setTimeout(() => { 12 // Yay! Can invoke sync or async actions with `dispatch` 13 dispatch(increment()) 14 }, 1000) 15 } 16}
An action creator that returns a function to perform conditional dispatch:
1function incrementIfOdd() { 2 return (dispatch, getState) => { 3 const { counter } = getState() 4 5 if (counter % 2 === 0) { 6 return 7 } 8 9 dispatch(increment()) 10 } 11}
A thunk is a function that wraps an expression to delay its evaluation.
1// calculation of 1 + 2 is immediate 2// x === 3 3let x = 1 + 2 4 5// calculation of 1 + 2 is delayed 6// foo can be called later to perform the calculation 7// foo is a thunk! 8let foo = () => 1 + 2
The term originated as a humorous past-tense version of "think".
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:
1import { createStore, applyMiddleware } from 'redux' 2import { thunk } from 'redux-thunk' 3import rootReducer from './reducers' 4 5// Note: this API requires redux@>=3.1.0 6const store = createStore(rootReducer, applyMiddleware(thunk)) 7 8function fetchSecretSauce() { 9 return fetch('https://www.google.com/search?q=secret+sauce') 10} 11 12// These are the normal action creators you have seen so far. 13// The actions they return can be dispatched without any middleware. 14// However, they only express “facts” and not the “async flow”. 15 16function makeASandwich(forPerson, secretSauce) { 17 return { 18 type: 'MAKE_SANDWICH', 19 forPerson, 20 secretSauce, 21 } 22} 23 24function apologize(fromPerson, toPerson, error) { 25 return { 26 type: 'APOLOGIZE', 27 fromPerson, 28 toPerson, 29 error, 30 } 31} 32 33function withdrawMoney(amount) { 34 return { 35 type: 'WITHDRAW', 36 amount, 37 } 38} 39 40// Even without middleware, you can dispatch an action: 41store.dispatch(withdrawMoney(100)) 42 43// But what do you do when you need to start an asynchronous action, 44// such as an API call, or a router transition? 45 46// Meet thunks. 47// A thunk in this context is a function that can be dispatched to perform async 48// activity and can dispatch actions and read state. 49// This is an action creator that returns a thunk: 50function makeASandwichWithSecretSauce(forPerson) { 51 // We can invert control here by returning a function - the "thunk". 52 // When this function is passed to `dispatch`, the thunk middleware will intercept it, 53 // and call it with `dispatch` and `getState` as arguments. 54 // This gives the thunk function the ability to run some logic, and still interact with the store. 55 return function (dispatch) { 56 return fetchSecretSauce().then( 57 sauce => dispatch(makeASandwich(forPerson, sauce)), 58 error => dispatch(apologize('The Sandwich Shop', forPerson, error)), 59 ) 60 } 61} 62 63// Thunk middleware lets me dispatch thunk async actions 64// as if they were actions! 65 66store.dispatch(makeASandwichWithSecretSauce('Me')) 67 68// It even takes care to return the thunk’s return value 69// from the dispatch, so I can chain Promises as long as I return them. 70 71store.dispatch(makeASandwichWithSecretSauce('My partner')).then(() => { 72 console.log('Done!') 73}) 74 75// In fact I can write action creators that dispatch 76// actions and async actions from other action creators, 77// and I can build my control flow with Promises. 78 79function makeSandwichesForEverybody() { 80 return function (dispatch, getState) { 81 if (!getState().sandwiches.isShopOpen) { 82 // You don’t have to return Promises, but it’s a handy convention 83 // so the caller can always call .then() on async dispatch result. 84 85 return Promise.resolve() 86 } 87 88 // We can dispatch both plain object actions and other thunks, 89 // which lets us compose the asynchronous actions in a single flow. 90 91 return dispatch(makeASandwichWithSecretSauce('My Grandma')) 92 .then(() => 93 Promise.all([ 94 dispatch(makeASandwichWithSecretSauce('Me')), 95 dispatch(makeASandwichWithSecretSauce('My wife')), 96 ]), 97 ) 98 .then(() => dispatch(makeASandwichWithSecretSauce('Our kids'))) 99 .then(() => 100 dispatch( 101 getState().myMoney > 42 102 ? withdrawMoney(42) 103 : apologize('Me', 'The Sandwich Shop'), 104 ), 105 ) 106 } 107} 108 109// This is very useful for server side rendering, because I can wait 110// until data is available, then synchronously render the app. 111 112store 113 .dispatch(makeSandwichesForEverybody()) 114 .then(() => 115 response.send(ReactDOMServer.renderToString(<MyApp store={store} />)), 116 ) 117 118// I can also dispatch a thunk async action from a component 119// any time its props change to load the missing data. 120 121import { connect } from 'react-redux' 122import { Component } from 'react' 123 124class SandwichShop extends Component { 125 componentDidMount() { 126 this.props.dispatch(makeASandwichWithSecretSauce(this.props.forPerson)) 127 } 128 129 componentDidUpdate(prevProps) { 130 if (prevProps.forPerson !== this.props.forPerson) { 131 this.props.dispatch(makeASandwichWithSecretSauce(this.props.forPerson)) 132 } 133 } 134 135 render() { 136 return <p>{this.props.sandwiches.join('mustard')}</p> 137 } 138} 139 140export default connect(state => ({ 141 sandwiches: state.sandwiches, 142}))(SandwichShop)
MIT
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
1 existing vulnerabilities detected
Details
Reason
Found 11/19 approved changesets -- score normalized to 5
Reason
2 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 1
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Score
Last Scanned on 2024-11-18
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More