Thunk middleware for Redux

Overview

Redux Thunk

Thunk middleware for Redux.

build status npm version npm downloads

npm install redux-thunk

yarn add redux-thunk

Note on 2.x Update

Most tutorials today assume that you're using Redux Thunk 1.x. You may run into issues when you run their code with 2.x. If you use Redux Thunk 2.x in CommonJS environment, don’t forget to add .default to your import:

- const ReduxThunk = require('redux-thunk')
+ const ReduxThunk = require('redux-thunk').default

If you used ES modules, you’re already all good:

import ReduxThunk from 'redux-thunk'; // no changes here 😀

Additionally, since 2.x, we also support a UMD build:

const ReduxThunk = window.ReduxThunk.default;

As you can see, it also requires .default at the end.

Why Do I Need This?

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:

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.

Motivation

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:

const INCREMENT_COUNTER = 'INCREMENT_COUNTER';

function increment() {
  return {
    type: INCREMENT_COUNTER,
  };
}

function incrementAsync() {
  return (dispatch) => {
    setTimeout(() => {
      // Yay! Can invoke sync or async actions with `dispatch`
      dispatch(increment());
    }, 1000);
  };
}

An action creator that returns a function to perform conditional dispatch:

function incrementIfOdd() {
  return (dispatch, getState) => {
    const { counter } = getState();

    if (counter % 2 === 0) {
      return;
    }

    dispatch(increment());
  };
}

What’s a thunk?!

A thunk is a function that wraps an expression to delay its evaluation.

// calculation of 1 + 2 is immediate
// x === 3
let x = 1 + 2;

// calculation of 1 + 2 is delayed
// foo can be called later to perform the calculation
// foo is a thunk!
let foo = () => 1 + 2;

The term originated as a humorous past-tense version of "think".

Installation

npm install redux-thunk

Then, to enable Redux Thunk, use applyMiddleware():

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';

// Note: this API requires [email protected]>=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:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

// Note: this API requires [email protected]>=3.1.0
const store = createStore(rootReducer, applyMiddleware(thunk));

function fetchSecretSauce() {
  return fetch('https://www.google.com/search?q=secret+sauce');
}

// These are the normal action creators you have seen so far.
// The actions they return can be dispatched without any middleware.
// However, they only express “facts” and not the “async flow”.

function makeASandwich(forPerson, secretSauce) {
  return {
    type: 'MAKE_SANDWICH',
    forPerson,
    secretSauce,
  };
}

function apologize(fromPerson, toPerson, error) {
  return {
    type: 'APOLOGIZE',
    fromPerson,
    toPerson,
    error,
  };
}

function withdrawMoney(amount) {
  return {
    type: 'WITHDRAW',
    amount,
  };
}

// Even without middleware, you can dispatch an action:
store.dispatch(withdrawMoney(100));

// But what do you do when you need to start an asynchronous action,
// such as an API call, or a router transition?

// Meet thunks.
// 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) {
  // 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) {
    return fetchSecretSauce().then(
      (sauce) => dispatch(makeASandwich(forPerson, sauce)),
      (error) => dispatch(apologize('The Sandwich Shop', forPerson, error)),
    );
  };
}

// Thunk middleware lets me dispatch thunk async actions
// as if they were actions!

store.dispatch(makeASandwichWithSecretSauce('Me'));

// It even takes care to return the thunk’s return value
// from the dispatch, so I can chain Promises as long as I return them.

store.dispatch(makeASandwichWithSecretSauce('My partner')).then(() => {
  console.log('Done!');
});

// In fact I can write action creators that dispatch
// actions and async actions from other action creators,
// and I can build my control flow with Promises.

function makeSandwichesForEverybody() {
  return function(dispatch, getState) {
    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();
    }

    // We can dispatch both plain object actions and other thunks,
    // which lets us compose the asynchronous actions in a single flow.

    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'),
        ),
      );
  };
}

// This is very useful for server side rendering, because I can wait
// until data is available, then synchronously render the app.

store
  .dispatch(makeSandwichesForEverybody())
  .then(() =>
    response.send(ReactDOMServer.renderToString(<MyApp store={store} />)),
  );

// I can also dispatch a thunk async action from a component
// any time its props change to load the missing data.

import { connect } from 'react-redux';
import { Component } from 'react';

class SandwichShop extends Component {
  componentDidMount() {
    this.props.dispatch(makeASandwichWithSecretSauce(this.props.forPerson));
  }

  componentDidUpdate(prevProps) {
    if (prevProps.forPerson !== this.props.forPerson) {
      this.props.dispatch(makeASandwichWithSecretSauce(this.props.forPerson));
    }
  }

  render() {
    return <p>{this.props.sandwiches.join('mustard')}</p>;
  }
}

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:

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. Using ES2015 shorthand property names can make this more concise.

const api = "http://www.example.com/sandwiches/";
const whatever = 42;

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

Comments
  • Make typings compatible with Redux 4.0.0

    Make typings compatible with Redux 4.0.0

    Partially fixes #169.

    BREAKING: It only supports TypeScript 2.4.0 or later.

    Changed ThunkAction<R, S, E> to ThunkAction<R, S, E, A>, where R is the return type of the thunk function, S is the type of root state, E is the type of extra arguments, A should be all actions that can be dispatched.

    ~Due to the limitation of current implementation, I'm not sure if R, S, E, A could be inferred.~ (UPDATE: I changed the implementation a little bit. I believe R, S, E, could be inferred in store.dispatch(). Changes needed in type definition for redux to make A inferable. )So a potentially better solution is to create a type for thunk actions by yourself and specify root states and all actions that can be dispatched.

    Example:

    type SideEffect<T> = ThunkAction<Promise<T>, RootState, {}, RootAction>
    

    Here I assume all my thunk functions return a promise of something. Then my thunk function returns a SideEffect<T>.

    export function asyncFunc(): SideEffect<string> {
      return async (dispatch, getState) => {
        dispatch({ type: ActionTypes.ASYNC });
        await timeout(1000);
        dispatch({ type: ActionTypes.ASYNC_FULFILLED });
        await timeout(1000);
        dispatch({ type: 'INVALID_ACTION_TYPE' });
        return 'NICE!';
      };
    }
    

    Then you can check the typings of dispatch and getState.

    Naturally it also makes dispatching type-safe, too.

    opened by Cryrivers 58
  • Use with TypeScript 2.0  (@types/redux-thunk)

    Use with TypeScript 2.0 (@types/redux-thunk)

    Hi

    I'm attempting to use redux-thunk with TypeScript 2.0. The definitions from npm install @types/redux-thunk is as follows:

    import * as Redux from "redux";
    import { Middleware } from "redux";
    
    export as namespace ReduxThunk;
    
    declare const thunk: Middleware & {
        withExtraArgument(extraArgument: any): Middleware;
    };
    export default thunk;
    
    declare module 'redux' {
        export type ThunkAction<R, S, E> = (dispatch: Dispatch<S>, getState: () => S, extraArgument: E) => R;
    
        export interface Dispatch<S> {
            <R, E>(asyncAction: ThunkAction<R, S, E>): R;
        }
    }
    

    The above appears to be completely different the one in the repo ?

    I'm creating my store like this:

        var middleware = [
            thunk
        ];
    
        var store = createStore(
            combineReducers({
                things1: Reducer1,
                things2: Reducer2
            }),
            initialState,
            compose(
                applyMiddleware(...middleware),
                devToolsAvailable() ? window.devToolsExtension() : f => f
            )
        );
    

    Then trying to initiate a thunk like this (I've copied the body of the function into the dispatch call for simplicity, it is returned from an action creator in my real code):

    store.dispatch((dispatch: Redux.Dispatch<State>, getState: () => State) => {
            if (!getState().things1.loading) {
                dispatch(loadStart());
                loadStaticData('things.json', {json: true})
                    .then((data: Things[]) => {
                        dispatch(loadComplete(data));
                    })
                    .catch((err) => {
                        dispatch(loadFailed(err));
                    });
            }
        })
    

    Unfortunately the error I get back is:

    [ts] Argument of type '(dispatch: Dispatch<State>, getState: () => State) => void' is not assignable to parameter of type 'Action'.
           Property 'type' is missing in type '(dispatch: Dispatch<State>, getState: () => State) => void'.
    

    So it looks like the defs available through npm aren't working (or I am missing something!).

    Please could someone confirm:

    • Are the typings available from npm current?
    • and if so, what am I missing in my example above?

    Thanks guys!!

    opened by dupski 47
  • Discussion: improving the developer experience for TypeScript users by making changes in the declaration file and adding documentation for types

    Discussion: improving the developer experience for TypeScript users by making changes in the declaration file and adding documentation for types

    I think it's clear that Redux Thunk doesn't provide the best experience for TypeScript developers. A Google search for “redux thunk typescript” yields many results with conflicting and outdated information with different ways to do the same thing. As a TypeScript developer, trying to enter this space can become frustrating very quickly. This is why I'd like to propose some changes we can make to improve this situation.

    Breaking the single-letter naming convention for generic types

    The most used naming convention for generics in the TypeScript community is using single-letters for type names. It's also what's used in the official TypeScript documentation. While this can work well for simple components that don't require much explanation, it can become quite tedious to work with as the component you're working with becomes more complex.

    Take this type, for example.

    export type ThunkAction<R, S, E, A extends Action> = (
       dispatch: ThunkDispatch<S, E, A>,
       getState: () => S,
       extraArgument: E
    ) => R;
    

    Without actually looking at the inside code of the type, the only variable type I could guess was S (which is the store state). Only when you start looking at the code, it becomes apparent that R is the result type by looking at which type the function returns, A is an Action by looking at what it's extending and that E is the extra argument by looking at its property name. This also means that if you're using an IDE, the parameter (or generic) info become virtually useless as you'll have to look at the definition anyway because it only works with descriptive names.

    This is why I think we should consider using one of these naming conventions:

    ThunkAction<ResultType, StateType, ExtraArgumentType, ActionType extends Action>
    

    or

    ThunkAction<TResult, TState, TExtraArgument, TAction extends Action>
    

    I personally prefer the second one, as I've seen other codebases use it before and it also prevents you from having to write ActionType, which could conflict with another type you might have in a codebase using Redux.

    The main downside of changing the naming convention is that we would be breaking the convention that's used in most TypeScript codebases as well as in official documentation. Ironically, I think it would improve readability.

    Writing documentation on how to use the types with real world examples

    There are 3 components in the current declaration file: ThunkDispatch, ThunkAction and ThunkMiddleware. While these names are fairly descriptive and self-explanatory, I think new Redux-TypeScript users would benefit greatly from official documentation with some good examples. At times, it can be difficult to use all the types correctly in conjunction with each other due to the way Redux is designed. This documentation could fit well into a separate TypeScript section on the official Redux documentation webpage, or we could keep it simple without going too much in depth and just put comments into the declarations file. The problem is that people might not always look at the declarations file for documentation.

    I'm interested to see what everyone thinks of these two proposals, and what else we could do to help the TypeScript community.

    opened by samjmck 37
  • TypeScript Error in Middleware

    TypeScript Error in Middleware

    The overloading of Dispatch by redux-thunk breaks middlewares that only handle standard action objects (as apposed to thunks).

    Example:

    import {Action, Dispatch, Middleware, Store} from 'redux';
    import {IAppState} from '../reducers';
    
    export const middleware: Middleware = (store: Store<IAppState>) => (next: Dispatch<IAppState>) => (action: Action) => {
      // Do something with the action ...
      next(action);
    };
    

    The resulting error is:

    Type '(store: Store<IAppState>) => (next: Dispatch<IAppState>) => (action: Action) => void' is not assignable to type 'Middleware'.
      Type '(next: Dispatch<IAppState>) => (action: Action) => void' is not assignable to type '(next: Dispatch<any>) => Dispatch<any>'.
        Type '(action: Action) => void' is not assignable to type 'Dispatch<any>'.
          Types of parameters 'action' and 'asyncAction' are incompatible.
            Type '(dispatch: Dispatch<any>, getState: () => any, extraArgument: any) => any' is not assignable to type 'Action'.
              Property 'type' is missing in type '(dispatch: Dispatch<any>, getState: () => any, extraArgument: any) => any'.
    

    A possible fix to remove the compiler error would be to declare a union type for the Action, i.e. Action | Redux.ThunkAction<any, IAppState, any>:

    export const middleware: Middleware = (store: Store<IAppState>) => (next: Dispatch<IAppState>) => (action: Action | Redux.ThunkAction<any, IAppState, any>) => {
      // Do something with the action ...
      next(action as Action);
    };
    

    But this is incorrect if your middleware only handles Action!

    The better solution would be to declare a Dispatch interface within the redux-thunk module that extends Redux.Dispatch. This Dispatch could then be used in action creators that return a ThunkAction:

    import {IAppState} from '../reducers';
    import {ThunkAction, Dispatch} from 'redux-thunk';
    
    export function thunkedActionCreator(): ThunkAction<void, IAppState, void> {
      return (dispatch: Dispatch<IAppState>, getState: () => IAppState): void => {
        // Do something async and dispatch actions or other thunks ...
      };
    }
    

    Middlewares on the other hand would use Redux.Dispatch (see middleware example above).

    opened by unstubbable 37
  • middleware is not a function

    middleware is not a function

    I can't tell if this is a redux-thunk or a redux issue.

    I have a store like this:

    const store = compose(
        applyMiddleware(
            thunk,
            logger
        )
    )(createStore)(counter);
    

    This results in an error message:

    ./node_modules/redux/lib/utils/applyMiddleware.js:50
            return middleware(middlewareAPI);
                   ^
    
    TypeError: middleware is not a function
        at ./node_modules/redux/lib/utils/applyMiddleware.js:50:16
        at Array.map (native)
        at ./node_modules/redux/lib/utils/applyMiddleware.js:49:27
        at Object.<anonymous> (./index.js:63:105)
        at Module._compile (module.js:425:26)
        at Object.Module._extensions..js (module.js:432:10)
        at Module.load (module.js:356:32)
        at Function.Module._load (module.js:311:12)
        at Function.Module.runMain (module.js:457:10)
        at startup (node.js:136:18)
    

    If I comment out thunk above, it continues:

    const store = compose(
        applyMiddleware(
            // thunk,
            logger
        )
    )(createStore)(counter);
    
    store.dispatch({ type: INCREMENT });
    store.dispatch({ type: INCREMENT });
    store.dispatch({ type: DECREMENT });
    
    $ node --harmony_default_parameters --harmony_destructuring index.js
    will dispatch { type: 'INCREMENT' }
    state after dispatch 1
    will dispatch { type: 'INCREMENT' }
    state after dispatch 2
    will dispatch { type: 'DECREMENT' }
    state after dispatch 1
    
    opened by johnjelinek 34
  • Add overload for bindActionCreators

    Add overload for bindActionCreators

    As per #223, redux's bindActionCreators only works nicely for standard action creators. This implementation infers the return type of ThunkActions so the application could respond accordingly. E.g. action fires an XHR, the application has no way of knowing when the XHR has resolved, other than through watching the state. This way, you can now have promise resolution in your application outside of the redux store.

    I've updated the TypeScript version to 3.1, this gives us access to the Parameters generic, the ReturnType generic, and conditional types.

    Feedback welcome

    Note, the should fix the concerns from the now closed #213

    opened by RMHonor 29
  • Create new npm release

    Create new npm release

    Feature Request

    There are a lot of good updates since the last npm release over 2 years ago. https://github.com/reduxjs/redux-thunk/compare/v2.3.0...master

    It'd be really great if whoever has access could cut a new release.

    opened by tony-scio 21
  • redux-thunk not waiting for my promise to be fulfilled

    redux-thunk not waiting for my promise to be fulfilled

    I have the following setup following your examples for chaining async actions:

    // final action
    function finalAction (status) {
      return {
        type: 'AUTH_STATUS'
        , status
    }
    
    // thunk action
    function thunkAction () {
      return (dispatch, getState) => {
        return getStatusApi()
        .then((status) => {
          return dispatch(finalAction(status))
        })
        .catch((err) => {
          return dispatch({type: 'AUTH_ERROR'})
        })
      }
    }
    
    // api function returning another promise
    function getStatusApi () {
      return myAsyncApiCall().then((res) => {
        return res.status
      })
    }
    
    // dispatch
    store.dispatch(thunkAction())
    .then(() => {
      // the end
    })
    

    What happens is that the flow is like this:

    store.dispatch
    thunkAction
    getStatusApi
    end
    myAsyncApiCall
    finalAction
    reducer
    

    For one reason or another store.dispatch resolves before myAsyncApiCall is resolved. I either receive then a TypeError or if wrapping the whole into a promise an undefined action error. Any idea?

    opened by alexanderharm 21
  • Example with Typescript, react-redux, and redux-thunk

    Example with Typescript, react-redux, and redux-thunk

    So glad to see redux-thunk has great support for Typescript and Redux v4. Where is the best place to view an up to date example of a correctly typed reducer, actions, and a connected component with redux-thunk? This test is a good start: https://github.com/reduxjs/redux-thunk/blob/master/test/typescript.ts But I can not seem to find an up to date example of what a correctly typed connected component should look like. Specifically I am looking for something that shows mapStateToProps, mapDispatchToProps, and the props interface for the component.

    opened by jfbloom22 20
  • Add Prettier

    Add Prettier

    Uses the following libraries to make this repo more contributor-friendly:

    ~~Automatic npm/GitHub release~~ 📦 ⬆️

    ~~This PR (if merged into master) and any future PRs merged directly into master will trigger an npm & GitHub release + changelog. This is done via @jedmao/semantic-release-npm-github-config, as mentioned in Semantic Release Community Configurations.~~

    ~~This was done in an effort to make maintenance and releases less of a burden to maintainers.~~

    😀 ❤️

    ~~Important!~~ 🚨

    ~~Before merging this PR (if you so decide), ensure that the following secret environment variables are set in your Travis-CI settings:~~

    opened by jednano 13
  • dispatch not returning a promise

    dispatch not returning a promise

    My ActionCreator looks like this :

    export function resetRiskProcessCard(cardKey) { return (dispatch) => { dispatch({ type: Actions.RESET_RISK_PROCESS_CARD, cardKey }); } }

    And I'm calling it like this

    this.props.dispatch(ActionCreators.Risk.resetRiskProcessCard(cardKey)).then(() => { console.log('then is called !!'); });

    I get the following error

    Uncaught TypeError: Cannot read property 'then' of undefined

    opened by gauravChaturvedi 13
  • Add ability to spy on dispatch called by thunks

    Add ability to spy on dispatch called by thunks

    Fixes #335

    2 unit tests were added that don't pass with the current implementation and do pass with fixed implementation

    Generated code also keeps the references for dispatch and getState updated

    image
    opened by danyg 1
  • Current implemention doesn't allow Jest or any other mock tool to spy on dispatch or getState

    Current implemention doesn't allow Jest or any other mock tool to spy on dispatch or getState

    Bug Report

    The current implementation doesn't allow spying or mock store.dispatch or store.getState as currently, the definition of createThunkMiddleware dereference store. dispatch and getState keep the value of creation time, when the store is created, preventing in architectures when the store is built on import time (singleton) to spy or mock the response of these two methods on the store.

    The solution would be to not dereference it so that every time a thunk is invoked the current implementation of these two methods is used.

    A PR is provided with tests for the solution.

    Package name / version

    [email protected]

    Description

    • Create a store with a thunk which dispatches an action
    • use jest.spyOn(store, 'dispatch') or similar tooling like sinon
    • expect the dispatch to have been called with the dispatched action
    • Fails to find such action as the dispatch invoked by the thunk is the original dispatch (store dispatch) and not the monkey patched one by jest

    Expected behaviour

    • Create a store with a thunk which dispatches an action
    • in test environment use jest.spyOn(store, 'dispatch') or similar tooling like sinon
    • expect the dispatch to have been called with the dispatched action
    • EXPECTED: the assertion to pass as thunk uses the monkey-patched implementation of dispatch.

    Environment

    • OS: OSX 12.2.1
    • Node/npm version: [e.g., Node 16.18.0/npm 8.19.2]
    • Browser: N/A

    Additional context / screenshots

    Generated code store reference at store creation time

    image
    opened by danyg 2
  • ThunkAction is not assignable to parameter of type 'AnyAction'.

    ThunkAction is not assignable to parameter of type 'AnyAction'.

    Bug Report

    Package name / version

    [email protected]

    Description

    I am trying to use a simple method from my store:

    store.dispatch(ThunkAction);
    

    It is working on run time, but I am receiving an error message on Typescript:

    TS2345: Argument of type 'ThunkAction<Promise<AuthorizationDto | null>, State, unknown, SetAuthorizationAction>' is not assignable to parameter of type 'AnyAction'.   Property 'type' is missing in type 'ThunkAction<Promise<AuthorizationDto | null>, State, unknown, SetAuthorizationAction>' but required in type 'AnyAction'. 
    

    I already tried to import the extend-redux like that:

    import 'redux-thunk/extend-redux';
    

    But the problem is the run time does not find file =S.

    Screen Shot 2022-04-13 at 3 36 16 PM

    I already tried every single solution that's I found on the previous issues, but non of them worked for me.

    Steps to reproduce

    • Install the redux-thunk using "npm install"
    • Create a ThunkAction
    • Call the store.dispatch(ThunkAction)
    • See typescript Type error

    Expected behavior

    No error message from typescript when using store.dispatch(ThunkAction)

    Environment

    • OS: macOS Monterey 12.3.1
    • Node/npm version: node v16.14.2 / npm 8.5
    • Platform: React Native iOS/Android
    opened by mendesbarreto 34
Releases(v2.4.2)
  • v2.4.2(Nov 4, 2022)

    This release removes an unused TS type that caused errors when users were type-checking libraries in node_modules.

    What's Changed

    • Remove unused type by @antoniopresto in https://github.com/reduxjs/redux-thunk/pull/328

    Full Changelog: https://github.com/reduxjs/redux-thunk/compare/v2.4.1...v2.4.2

    Source code(tar.gz)
    Source code(zip)
  • v2.4.1(Nov 26, 2021)

    This release adds an explicit plain action overload to the ThunkDispatch TS type to better handle inference of the return value in some cases.

    What's Changed

    • Improve action return value resolution by @markerikson in https://github.com/reduxjs/redux-thunk/pull/327

    Full Changelog: https://github.com/reduxjs/redux-thunk/compare/v2.4.0...v2.4.1

    Source code(tar.gz)
    Source code(zip)
  • v2.4.0(Oct 26, 2021)

    This very overdue release makes several major improvements to the TypeScript types, and converts the actual source to TypeScript. Sorry for the delay!

    Changelog

    TypeScript Improvements

    This release fixes several outstanding issues that had been reported with the types. An extra overload has been added to let TS correctly understand some generically-typed values being passed to dispatch, and the overloads have been reworked for additional compatibility.

    There's also a new ThunkActionDispatch type that can be used to represent how bindActionCreators turns bound thunks into (arg) => thunkReturnValue.

    Additionally, all of the generic args have been giving meaningful names instead of one-letter abbreviations (S -> State, E -> ExtraArgument, etc), and we've added descriptive comments in the type definitions for clarity.

    Optional Global Dispatch Type Extension

    Most Redux apps have the thunk middleware enabled, but the default Dispatch and bindActionCreator types only know about the standard behavior of a basic Redux store without any middleware. The thunk middleware types add to that type behavior, so that Dispatch knows dispatching a thunk can actually return a value such as a Promise.

    We generally recommend inferring the type of dispatch and using that to create reusable types, including creating pre-typed hooks. However, some users may prefer to globally augment the Dispatch type to always use the additional thunk behavior.

    You can now import 'redux-thunk/extend-redux' to globally augment the Dispatch type as an opt-in change in behavior.

    Codebase Converted to TypeScript

    We've gone ahead and converted the actual source to TS. Since the source was only 15-ish lines to begin with, most of the "conversion" time was just trying to convince TS that assigning thunk.extraArgument = createThunkMiddleware was a legal operation :)

    We also updated the build tooling:

    • Babel updates
    • Rollup for the UMDs instead of Webpack
    • Github Actions for CI instead of Travis

    Finally, the README has been updated with newer instructions and usage information.

    What's Changed

    • Change misleading parameter name for overload of ThunkDispatch by @jmrog in https://github.com/reduxjs/redux-thunk/pull/216
    • --save no longer needed by @JoeCortopassi in https://github.com/reduxjs/redux-thunk/pull/217
    • Allow action to be typed with any by @laat in https://github.com/reduxjs/redux-thunk/pull/219
    • Add overload for bindActionCreators by @RMHonor in https://github.com/reduxjs/redux-thunk/pull/224
    • promote gender neutral docs by @beatfactor in https://github.com/reduxjs/redux-thunk/pull/234
    • Clarify terminology by @jmm in https://github.com/reduxjs/redux-thunk/pull/237
    • Provide more informative names for TypeScript type params by @agwells in https://github.com/reduxjs/redux-thunk/pull/243
    • Add peer dependency on redux 4.0 by @hedgepigdaniel in https://github.com/reduxjs/redux-thunk/pull/251
    • chore: remove 2015 preset and add env by @hozefaj in https://github.com/reduxjs/redux-thunk/pull/236
    • #248 Add union overload to ThunkDispatch by @Philipp91 in https://github.com/reduxjs/redux-thunk/pull/255
    • fix: extraThunkArgument types by @jedmao in https://github.com/reduxjs/redux-thunk/pull/260
    • Upgrade dependencies by @jedmao in https://github.com/reduxjs/redux-thunk/pull/261
    • Add Prettier by @jedmao in https://github.com/reduxjs/redux-thunk/pull/262
    • fix: typo TExtraThunkARg -> TExtraThunkArg by @jedmao in https://github.com/reduxjs/redux-thunk/pull/263
    • declare this package as having no side effects by @VincentBailly in https://github.com/reduxjs/redux-thunk/pull/267
    • Reflect rename of Redux Starter Kit by @travigd in https://github.com/reduxjs/redux-thunk/pull/270
    • Correct destructuring example by @telegraham in https://github.com/reduxjs/redux-thunk/pull/272
    • Fix link by @mhienle in https://github.com/reduxjs/redux-thunk/pull/276
    • feat(ts): add Dispatch overload to redux module by @iamandrewluca in https://github.com/reduxjs/redux-thunk/pull/278
    • docs: fix link for applyMiddleware by @iamandrewluca in https://github.com/reduxjs/redux-thunk/pull/279
    • Improved wording in README.md by @haricharanbole in https://github.com/reduxjs/redux-thunk/pull/293
    • chore: add yarn add line by @RichardBray in https://github.com/reduxjs/redux-thunk/pull/305
    • Use "sh" instead of "js" in install instructions by @EvanHahn in https://github.com/reduxjs/redux-thunk/pull/312
    • Remove redundant | by @Philipp91 in https://github.com/reduxjs/redux-thunk/pull/317
    • Use GitHub Actions by @nickmccurdy in https://github.com/reduxjs/redux-thunk/pull/318
    • Update TS dev tooling and GH Actions workflow by @markerikson in https://github.com/reduxjs/redux-thunk/pull/320
    • Move Redux module type extension into a separate imported file by @markerikson in https://github.com/reduxjs/redux-thunk/pull/321
    • Add CodeSandbox CI by @markerikson in https://github.com/reduxjs/redux-thunk/pull/323
    • Convert codebase to TS and update build tooling by @markerikson in https://github.com/reduxjs/redux-thunk/pull/322
    • Remove Webpack config and try test build by @markerikson in https://github.com/reduxjs/redux-thunk/pull/324

    New Contributors

    • @jmrog made their first contribution in https://github.com/reduxjs/redux-thunk/pull/216
    • @JoeCortopassi made their first contribution in https://github.com/reduxjs/redux-thunk/pull/217
    • @laat made their first contribution in https://github.com/reduxjs/redux-thunk/pull/219
    • @RMHonor made their first contribution in https://github.com/reduxjs/redux-thunk/pull/224
    • @beatfactor made their first contribution in https://github.com/reduxjs/redux-thunk/pull/234
    • @jmm made their first contribution in https://github.com/reduxjs/redux-thunk/pull/237
    • @agwells made their first contribution in https://github.com/reduxjs/redux-thunk/pull/243
    • @hedgepigdaniel made their first contribution in https://github.com/reduxjs/redux-thunk/pull/251
    • @hozefaj made their first contribution in https://github.com/reduxjs/redux-thunk/pull/236
    • @Philipp91 made their first contribution in https://github.com/reduxjs/redux-thunk/pull/255
    • @jedmao made their first contribution in https://github.com/reduxjs/redux-thunk/pull/260
    • @VincentBailly made their first contribution in https://github.com/reduxjs/redux-thunk/pull/267
    • @travigd made their first contribution in https://github.com/reduxjs/redux-thunk/pull/270
    • @telegraham made their first contribution in https://github.com/reduxjs/redux-thunk/pull/272
    • @mhienle made their first contribution in https://github.com/reduxjs/redux-thunk/pull/276
    • @iamandrewluca made their first contribution in https://github.com/reduxjs/redux-thunk/pull/278
    • @haricharanbole made their first contribution in https://github.com/reduxjs/redux-thunk/pull/293
    • @RichardBray made their first contribution in https://github.com/reduxjs/redux-thunk/pull/305
    • @EvanHahn made their first contribution in https://github.com/reduxjs/redux-thunk/pull/312
    • @nickmccurdy made their first contribution in https://github.com/reduxjs/redux-thunk/pull/318
    • @markerikson made their first contribution in https://github.com/reduxjs/redux-thunk/pull/320

    Full Changelog: https://github.com/reduxjs/redux-thunk/compare/v2.3.0...v2.4.0

    Source code(tar.gz)
    Source code(zip)
  • v2.3.0(May 28, 2018)

    Hello! There's a new sheriff in town...

    This is only an update to the TypeScript typings for Redux 4.0 compatibility. After some discussion on the issues/PRs, we're going to be removing the typings completely in a 3.0 release soon. They will instead live in DefinitelyTyped, where they can be updated to match newer version of TypeScript and Redux at whatever pace they want to take. Farewell, typings! 🖖

    • Updated TypeScript typings for Redux 4.0 (#180 by @Cryrivers)
    Source code(tar.gz)
    Source code(zip)
  • v2.2.0(Jan 18, 2017)

  • v2.1.2(Jan 18, 2017)

  • v2.1.1(Jan 18, 2017)

  • v2.1.0(May 10, 2016)

    • Adds withExtraArgument for the cases when you want to inject a custom argument into all thunks. (#70)
    const store = createStore(
      reducer,
      applyMiddleware(thunk.withExtraArgument(api))
    )
    
    // later
    function fetchUser(id) {
      return (dispatch, getState, api) => {
        // you can use api here
      }
    }
    
    Source code(tar.gz)
    Source code(zip)
  • v2.0.1(Mar 6, 2016)

  • v2.0.0(Mar 6, 2016)

    Note: this release was botched. Read the notes here but install 2.0.1 (or later) instead :sweat_smile: .

    Breaking Changes

    If you used Redux Thunk from npm in CommonJS environment, you need to add .default to your requires:

    - var ReduxThunk = require('redux-thunk')
    + var ReduxThunk = require('redux-thunk').default
    

    If you used ES modules, you’re already all good:

    import ReduxThunk from 'redux-thunk' // no changes here 😀
    

    New Features

    UMD build

    Like with CommonJS build, you will need to grab the middleware from .default export:

    var ReduxThunk = window.ReduxThunk.default
    

    Grab the UMD build on npmcdn.

    ES modules build

    Rollup users can now use redux-thunk directly without commonjs plugin.

    Source code(tar.gz)
    Source code(zip)
  • v1.0.3(Dec 28, 2015)

    • Fixes a regression in IE8 (https://github.com/gaearon/redux-thunk/issues/45, https://github.com/gaearon/redux-thunk/commit/00f7fdb9b41e7445941692bc9c808f3769be22bd, https://phabricator.babeljs.io/T2817)
    Source code(tar.gz)
    Source code(zip)
  • v1.0.2(Dec 14, 2015)

  • v1.0.1(Dec 13, 2015)

  • v1.0.0(Sep 17, 2015)

  • v0.1.0(Jul 13, 2015)

Owner
Redux
Redux is a predictable state container for JavaScript apps.
Redux
RxJS middleware for action side effects in Redux using "Epics"

RxJS-based middleware for Redux. Compose and cancel async actions to create side effects and more. https://redux-observable.js.org Install This has pe

redux-observable 7.8k Dec 1, 2022
Analytics middleware for Redux

redux-analytics Analytics middleware for Redux. $ npm install --save redux-analytics Want to customise your metadata further? Check out redux-tap. Usa

Mark Dalgleish 490 Aug 5, 2022
A mock store for testing Redux async action creators and middleware.

redux-mock-store A mock store for testing Redux async action creators and middleware. The mock store will create an array of dispatched actions which

Redux 2.5k Nov 28, 2022
Redux Tutorial - share my experience regarding redux, react-redux and redux-toolkit

Redux Tutorial 1. Introduction to Redux 1.1 What is Redux & why Redux? A small JS Library for managing medium/large amount of states globally in your

Anisul Islam 36 Dec 1, 2022
A Higher Order Component using react-redux to keep form state in a Redux store

redux-form You build great forms, but do you know HOW users use your forms? Find out with Form Nerd! Professional analytics from the creator of Redux

Redux Form 12.6k Dec 1, 2022
redux-immutable is used to create an equivalent function of Redux combineReducers that works with Immutable.js state.

redux-immutable redux-immutable is used to create an equivalent function of Redux combineReducers that works with Immutable.js state. When Redux creat

Gajus Kuizinas 1.9k Nov 14, 2022
A chart monitor for Redux DevTools https://www.npmjs.com/package/redux-devtools-chart-monitor

Redux DevTools Chart Monitor This package was merged into redux-devtools monorepo. Please refer to that repository for the latest updates, issues and

Redux 293 Nov 13, 2022
A simple app for study react with redux, redux saga and typescript.

React com Redux, Redux-Saga e TypeScript. ?? Uma aplicação simple para entender o funcionamento do Redux e a melhor maneira de utiliza-lo junto com o

João Marcos Belanga 1 May 24, 2022
Redux - Create forms using Redux And React

Exercício de fixação Vamos criar formulários utilizando Redux! \o/ Antes de inic

Márcio Júnior 2 Jul 21, 2022
A lightweight state management library for react inspired by redux and react-redux

A lightweight state management library for react inspired by redux and react-redux

null 2 Sep 9, 2022
Official React bindings for Redux

React Redux Official React bindings for Redux. Performant and flexible. Installation Using Create React App The recommended way to start new apps with

Redux 22.5k Dec 7, 2022
DevTools for Redux with hot reloading, action replay, and customizable UI

Redux DevTools Developer Tools to power-up Redux development workflow or any other architecture which handles the state change (see integrations). It

Redux 13.2k Dec 2, 2022
Ruthlessly simple bindings to keep react-router and redux in sync

Project Deprecated This project is no longer maintained. For your Redux <-> Router syncing needs with React Router 4+, please see one of these librari

React Community 7.9k Dec 2, 2022
The official, opinionated, batteries-included toolset for efficient Redux development

Redux Toolkit The official, opinionated, batteries-included toolset for efficient Redux development (Formerly known as "Redux Starter Kit") Installati

Redux 8.8k Nov 30, 2022
Logger for Redux

Logger for Redux Now maintained by LogRocket! LogRocket is a production Redux logging tool that lets you replay problems as if they happened in your o

null 5.7k Dec 1, 2022
Selector library for Redux

Reselect Simple “selector” library for Redux (and others) inspired by getters in NuclearJS, subscriptions in re-frame and this proposal from speedskat

Redux 18.8k Dec 1, 2022
An alternative side effect model for Redux apps

redux-saga redux-saga is a library that aims to make application side effects (i.e. asynchronous things like data fetching and impure things like acce

Redux-Saga 22.3k Dec 3, 2022
Declarative Side Effects for Redux

Redux Data FX Declarative Side Effects for Redux. It helps you keep your business logic and effectful code separate. The idea is simple: in addition o

Matthieu Béteille 53 Jun 30, 2021
:recycle: higher order reducer to add undo/redo functionality to redux state containers

redux undo/redo simple undo/redo functionality for redux state containers Protip: Check out the todos-with-undo example or the redux-undo-boilerplate

Daniel Bugl 2.8k Dec 4, 2022