Redux Thunk FSA
raw JSON → 4.1.1 verified Sat Apr 25 auth: no javascript
FSA-compliant thunk middleware for Redux that extends the standard redux-thunk package to support Flux Standard Actions (FSA). Current stable version is 4.1.1, released 2024-02-15, with regular updates. It allows action creators to return functions (thunks) for asynchronous or conditional dispatching, but with the added ability to handle FSA-compliant actions where the payload contains a dispatch function. Differentiates from redux-thunk by integrating seamlessly with redux-promise for async FSA patterns. Ships TypeScript definitions and supports React Native. Maintained by Makeomatic.
Common errors
error TypeError: middleware is not a function ↓
cause Passing middleware directly to createStore without applyMiddleware.
fix
Use applyMiddleware: const store = createStore(reducer, applyMiddleware(ReduxThunk));
error Cannot find module 'redux-thunk-fsa' ↓
cause Module not installed, or import path is incorrect.
fix
Install with npm install redux-thunk-fsa and ensure import path is 'redux-thunk-fsa' (not 'redux-thunk').
error Error: Actions must be plain objects. Use custom middleware for async actions. ↓
cause Thunk middleware not applied; async action creator returned a function but middleware didn't handle it.
fix
Ensure applyMiddleware(ReduxThunk) is used when creating the store.
error Cannot read properties of undefined (reading 'dispatch') ↓
cause Thunk function expects dispatch and getState as arguments, but they are undefined because middleware not applied or incorrectly configured.
fix
Verify store creation includes applyMiddleware(ReduxThunk) and that the thunk is correctly passed to dispatch.
Warnings
breaking Version 3.x changed import path from redux-thunk to redux-thunk-fsa ↓
fix Update import statements: use 'redux-thunk-fsa' instead of 'redux-thunk'
gotcha FSA support only works when payload contains a dispatch function; regular thunks without FSA still work. ↓
fix Ensure FSA actions follow the Flux Standard Action spec: { type, payload, error, meta }. For thunk payloads, use payload: dispatch => ...
deprecated The compose with multiple middlewares pattern using redux-thunk-fsa may conflict with devtools enhancer order. ↓
fix Always use compose(applyMiddleware(ReduxThunk), devtoolsEnhancer()) to maintain correct order.
gotcha In Node.js with ESM, you must use .mjs extension or set "type": "module" in package.json. ↓
fix Add {"type": "module"} in package.json or rename files to .mjs.
gotcha TypeScript type imports require 'import type' to avoid emitting value imports. ↓
fix Use import type { ThunkAction } from 'redux-thunk-fsa'
deprecated Calling applyMiddleware without ReduxThunk will not enable thunk functionality. ↓
fix Always include ReduxThunk in applyMiddleware arguments.
Install
npm install redux-thunk-fsa yarn add redux-thunk-fsa pnpm add redux-thunk-fsa Imports
- default import (reduxThunkFsa) wrong
import { ReduxThunk } from 'redux-thunk-fsa'correctimport ReduxThunk from 'redux-thunk-fsa' - createStore with middleware wrong
const store = createStore(reducer, ReduxThunk); // Missing applyMiddlewarecorrectimport { createStore, applyMiddleware } from 'redux'; import ReduxThunk from 'redux-thunk-fsa'; const store = createStore(reducer, applyMiddleware(ReduxThunk)); - compose with middleware wrong
const store = createStore(reducer, applyMiddleware(ReduxThunk), window.__REDUX_DEVTOOLS_EXTENSION__());correctimport { createStore, applyMiddleware, compose } from 'redux'; import ReduxThunk from 'redux-thunk-fsa'; const store = createStore(reducer, compose(applyMiddleware(ReduxThunk), window.__REDUX_DEVTOOLS_EXTENSION__?.())); - TypeScript types wrong
import { ThunkAction } from 'redux-thunk-fsa'correctimport type { ThunkAction, ThunkDispatch } from 'redux-thunk-fsa'
Quickstart
import { createStore, applyMiddleware } from 'redux';
import ReduxThunk from 'redux-thunk-fsa';
// Example reducer
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
default:
return state;
}
}
// Async action creator returning a thunk
function incrementAsync() {
return (dispatch) => {
setTimeout(() => {
dispatch({ type: 'INCREMENT' });
}, 1000);
};
}
// Create store with thunk middleware
const store = createStore(counter, applyMiddleware(ReduxThunk));
// Dispatch async action
store.dispatch(incrementAsync());
console.log(store.getState()); // 0 initially, then 1 after 1 second