Coder Social home page Coder Social logo

redux-thunk's People

Contributors

agwells avatar aikoven avatar antoniopresto avatar aryaemami59 avatar boyarskiy avatar chentsulin avatar dthree avatar ellbee avatar eskimojo14 avatar fiznool avatar gaafar avatar gaearon avatar hirose504 avatar iamandrewluca avatar ipetez avatar jedmao avatar laat avatar markerikson avatar mgol avatar mshaaban088 avatar nickmccurdy avatar philipp91 avatar rmhonor avatar ryota-murakami avatar syati avatar timdorr avatar twavv avatar vincentbailly avatar weslleyaraujo avatar wildhoney avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

redux-thunk's Issues

Release

Hi, thank you for this and redux.
Are you going to release 1.0 of this library?

default export

Although import thunkMiddleware from 'redux-thunk'; works, some code inspection tools (e.g. Webstorm ) complain that Default export is not declared in exported module. I am not sure if this is an issue with the way that the export is defined in the middleware, or is something that e.g. Webstorm cannot catch.

[Question]: what does thunk 2.x bring to the table?

First up - many thank you(s) for the greater redux ecosystem :) love all the amazing work you do and truly appreciate all you've given away (especially the wonderful egghead series).

Question - I've been using redux-thunk along with redux the last few months but noticed recently that this library is now in v2.0. I tried looking for a changelog or something to show "what is different / why upgrade" but didn't see anything explicit about the migration/etc.

For new users - what is the compelling reason to upgrade/what does 2.0 offer?

action is an object, not a function

I am not sure whether this is due to the libraries I used, but the following checking in redux-thunk/lib/index.js always yields false:

return typeof action === 'function' ? action(dispatch, getState) : next(action);

It turns out the typeof action == "object.
Here is the output of console.log(action):

Object {type: "PERFORM_ACTION", timestamp: 1448528834619}
action: (dispatch)
timestamp: 1448528834619
type: "PERFORM_ACTION"
__proto__: Object

In my case, the solution is to change the code into:

 return typeof action.action === 'function' ? action.action(dispatch, getState) : next(action);

Here are the libraries I use:

"body-parser": "~1.13.2",
"bootstrap": "^3.3.5",
"cookie-parser": "~1.3.5",
"debug": "~2.2.0",
"express": "~4.13.1",
"extract-text-webpack-plugin": "^0.9.1",
"foundation-sites": "^6.0.3",
"history": "^1.13.1",
"jade": "~1.11.0",
"jquery": "^2.1.4",
"lodash": "^3.10.1",
"morgan": "~1.6.1",
"react": "^0.14.3",
"react-dom": "^0.14.3",
"react-redux": "^4.0.0",
"react-router": "^1.0.0",
"redux": "^3.0.4",
"redux-logger": "^2.0.4",
"redux-router": "^1.0.0-beta4",
"redux-thunk": "^1.0.0",
"serve-favicon": "~2.3.0"

I use node v4.2.2 with latest version of Webpack and Babel

creating custom thunk middleware

Any interest in supporting more complex use cases for thunks (like injecting an API client)?

const export myAction = (data) => (dispatch, getState, helpers) => {
  return helpers.client.get(PATH, options).then(doStuff);
}

Doesn't need to be a breaking change; we can export a factory:

export const createThunkMiddleware = (any) => ({ dispatch, getState }) => next => action => {
  if (typeof action === 'function') {
    return action(dispatch, getState, any);
  }
  return next(action);
};

export default createThunkMiddleware();

Redux-thunk causing infinite loop in React/Redux application

I'm working on a webapp that's utilizing React with Redux. I have posted a similar message at the redux-thunk Github, but I think this might possibly be a more general issue with Redux middleware. I am currently using Redux-Thunk in a manner very similar to the example found here:
http://redux.js.org/docs/advanced/ExampleRedditAPI.html

When running my app, I see the following error in Chrome:

Uncaught RangeError: Maximum call stack size exceeded
(anonymous function) @ index.js:10
dispatch @ applyMiddleware.js:44
(anonymous function) @ index.js:12
dispatch @ applyMiddleware.js:44
(anonymous function) @ index.js:12
dispatch @ applyMiddleware.js:44
(anonymous function) @ index.js:12
dispatch @ applyMiddleware.js:44

Here's a link to my project:
https://github.com/jbri7357/redux-sample-app

Composition - Error Handling?

I've started writing my asynchronous actions like this:

export function fetchLocations(userId: string, locationIds: Array<string>) {
  return async function(dispatch: Function) : Promise<Array<Location>> {
    try {
      dispatch(startFetchingLocations(userId, locationIds))
      const locations = await SomeAPI.fetchLocations(userId, locationIds)
      dispatch(successfullyFetchedLocations(userId, locations))
      return locations
    } catch (e) {
      dispatch(failureFetchingLocations(userId))
      throw e
    }
  }
}

The idea is that these actions are composable/chainable (i.e. you can then() or await on dispatch, get the Promise result (locations above) and then do something else. However, these actions do not need to be chained, I've also got synchronous success and failure actions that my reducers listen for.

To make these asynchronous actions properly chainable, in addition to dispatching the failure message, they rethrow any errors. This means the chain can catch the error.

Chained use (Composition)

async function doStuffChained()
  try {
    const locations = await dispatch(fetchLocations(userId, locationIds))
   // Do some stuff with the returned locations
  } catch (e) {
    // Do something
  }
}

Regular use

function doStuff() {
  dispatch(fetchLocations(userId, locationIds))
}

The problem

The issue is when I want to use this action in a non-chainable fashion (e.g. doStuff) I get React Native complaining at me that I've got unhandled promise errors - because we rethrow our errors so they're chainable, but in doStuff we don't care about errors and are discarding dispatch's return value (in this case a Promise). Instead the errors are handled in the reducer thanks to my failureFetchingLocations() action.

I realise that I could change doStuff to:

function doStuff() {
  dispatch(fetchLocations(userId, locationIds)).catch(e => console.log(e))
}

However, this seems awfully peculiar and will break if I were to change my action to be synchronous. The asynchrony of the action is really an implementation detail, callers shouldn't need to know whether or not the action is asynchronous.

Instead of simply extending dispatch's behaviour, redux-thunk has broken its contract. We're now requiring dispatch to be used in an entirely different way, and it's unclear from looking at the code whether or not you need to handle dispatch errors or not. It's effectively a violation of Liskov's principle of substitution i.e. You cannot use redux-thunk's altered dispatch everywhere you would use redux's (default) dispatch.

EDIT: I realise Liskov's principle of substitution typically refers to OOP inheritance, but you get the gist.

Is there an existing solution for this problem?

A default error handler could perhaps be installed to gobble up the errors. That would prevent the violation of dispatch's contract i.e. you don't need to occasionally capture promise errors. I'm not sure how other people would find that solution though - also, it would need to be done in a way that doesn't break chaining.

Cannot read property 'type' of undefined when no function is explicitly returned on the action creator

Why does I get this error when I implement the action without the return function (and which is how @gaearon told me I should do here reduxjs/redux#994 (comment) )

export function createPlan() {
  return dispatch => {
    const planId = uuid();
    const exerciseId = uuid();

    dispatch({
      type: 'CREATE_PLAN',
      plan: {title: 'Treino A', exercises: [exerciseId], id: planId},
      id: planId
    });

    // return function(){
      dispatch({
        type: 'CREATE_EXERCISE',
        id: exerciseId,
        exercise: {
          id: exerciseId,
          title: 'CREATE_PLAN'
        }
      });
    // }
  };
}

image

but when I uncomment the return function it works?

I'm calling this action for the view, like this this.props.dispatch(this.actions.createPlan(id))

I'm missing something here?

dispatch & getState are undefined when dispatching action

Hello,

I'm new to redux and redux thunk.

I try to get asyncronous actions to work. My problem is getState and dispatch are undefined in the fonction that is dispatch.

Here is my store:

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

const createStoreWithMiddleware = applyMiddleware(
  thunk
)(createStore);

export default function configureStore(initialState) {
  const store = createStoreWithMiddleware(rootReducer, initialState);

  if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('./reducers', () => {
      const nextReducer = require('./reducers');
      store.replaceReducer(nextReducer);
    });
  }
  return store;
}

Here is my component appSideBar that trigger an action when loaded:

class appSideBar extends React.Component {
  componentDidMount(){
    this.props.actions.init();
  }
  render() {
    return (
      ...
    );
  }
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(appBarActions, dispatch)
  };
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(appSideBar);

As you can see, this.props.actions. refers to the dispatch function from the store

And here is my actions:

export var appBarActions={
  init:(dispatch, getState)=>{

    if (getState.isInitialized === true){
      return Promise.resolve();
    }else{
      if (context.applicationName!== undefined){
        return newPromise('/context.applicationName', 'GET').then(function(response){
          dispatch({ type: "init", response: response});
        }).catch(function(err){
          dispatch({ type: "error", err: err});
        });
      }else{
        console.error("no application name given");
        return Promise.resolve();
      }
    }
  }
}

Do you have any idea why dispatch and getState are undefined? is somethin wrong in my code?

I try to trigger actions "init" or "error" depending on the "newPromise" response and then update React component accordingly.

Thank you for helping

why pass (dispatch, getState) instead of (store) to thunks?

Is there a reason to only pass on (dispatch, getStore) explicitly to the thunk like you do:

function thunkMiddleware({ dispatch, getState }) {
  return next => action =>
    typeof action === 'function'
      ? action(dispatch, getState)
      : next(action);
}

Why not implementing it with the same interface as redux middlewares use by passing the whole store to the thunk:

function thunkMiddleware = store => next => action =>
  typeof action === 'function'
    ? action(store)
    : next(action);

`next` is not a function with [email protected]

After I made upgrades on npm as described down below, [email protected] threw the error next is not a function on line 12 of the index.js.

Upgrades:

redux: 1.0.1 -> 2.0.0
react-redux: 1.0.1 -> 2.1.0
redux-devtools: 1.1.0 -> 2.1.0

Once I rolled back to 1.x.x, everything worked again as expected.

Update: Ok, just looked at the code. I probably could have dropped the line number.

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).

Add README

Because I expect this to be, like, the most popular middleware for Redux.

Thunked action should be passed on to next middleware

This came up in discussion of pburtchaell/redux-promise-middleware#24.

In order to be able to use both redux-thunk and redux-promise-middleware in combination, it is important for the thunk middleware to pass on it's thunked action to the next middleware. So to fix my problem, I had to change the thunk middleware from this:

export default function thunkMiddleware({ dispatch, getState }) {
  return next => action =>
    typeof action === 'function' ?
      action(dispatch, getState) :
      next(action);
}

to this:

function myThunkMiddleware({ dispatch, getState }) {
  return next => action =>
    typeof action === 'function' ?
      next(action(dispatch, getState)) :
      next(action);
}

That seems like a generally useful improvement, and I can't think of any reason not to do it.

Please see the referenced issue for the full discussion.

Making dispatch + store available to middleware arguments.

When adding an extra argument, such as an API helper. Is it possible to make the store and dispatch available to the argument.

e.g. Adding a token from the store to all API requests.

const reduxThunkMiddleware = thunk.withExtraArgument(api);

and in the api argument:

// ...
function api(dispatch, getState) {
    return fetch('/authenticated/route', { token: getState().token });
}
// ...

Order of middleware stack, and thunk

I've been debugging an issue for the last while, and the crux of the issue is that thunk sat further down the middleware stack than it should, causing me some rather opaque errors.

In particular, devTools ran before it, and was throwing an exception as it tried to interpret the result returned from an action creator.

My fix involved changing from this

const finalCreateStore = compose(
  devTools(),
  applyMiddleware(thunk),
  persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/)),
  createStore
);

to this

const finalCreateStore = compose(
  applyMiddleware(thunk),
  devTools(),
  persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/)),
  createStore
);

Is it worthwhile stating on the README that thunk must be run before other middleware, or is this issue specific to devTools?

Logic in actions mix of concerns

After reading through the conceptual ideas behind redux I have one particular issue with regards to actions. It makes sense to me to use action creators as, if for no other reason, a means to maintain consistency. The problem I have, however, is when you start talking about middleware thunks applied to actions. This seems like a gross mixing of concerns, particularly if you see actions in a more familiar/typical role in an evented or messaging architecture. Should it not be that whomever receives the actions enforces the domain logic of (per the example here) "don't allow more than 3 todos"?

This may be nitpicking, but I am of the belief that mixing "something happened" events with "should we send this event?" is a crossing of concerns and will run you into trouble down the road. Perhaps one component really wants to know each and every time a new todo is added (maybe for displaying a "too many todos" error) while a second component will receive the action, but follows its own logic to disregard that action because it reads that there are too many todos already. This argument extends to the numerous other examples of decorating actions with domain logic. Maybe I'm missing the point, or thinking about this in the wrong paradigm, but it seems very limiting to have your actions responsible for performing tasks like fetching, updating, emitting more actions, etc. versus simply firing an action and letting some other components deal with that event.

It just overall seems like a bad idea to offer this action creation decoration as an example of thunk middleware.

TypeScript error om importing redux-thunk

with latest version of redux-thunk I am getting TypeScript error of:

Error:(24, 61) TS2304: Cannot find name 'thunkMiddleware'.

I already installed typings redux-thunk and included it.
here is the config:

capture

so it's not seeing the imported member,

as workaround added to definition file:

declare var thunkMiddleware:any;

regards

Sean

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?

redux-thunk passes a function into the reducers when creating the store

According to the docs:

Redux will call our reducer with an undefined state for the first time. This is our chance to return the initial state of our app

When using redux-thunk as the only middleware, a function is passed in as the initial state instead. Is there any documentation on what this is and how to handle it?

I'm reasonably new to this, so forgive me if I've missed a trick.

Question about appropriate testing strategy for dispatch returns

This is probably my limited understanding of async JS unit testing coming through, but I have a question about the appropriate strategy for testing actions dispatched by redux-thunk.

I have an action to log users out of a system:

export function logout() {
  return dispatch => {
    return request.del(`/session/logout`)
      .then(() => {
        setUserCookie({});
        dispatch(receiveUser({}));
      }, (error) => {
        dispatch(receiveUserError(error.message));
      });
  };
}

I'm using Jasmine as my testing framework, but I'm less interested in framework specifics as I am about testing the various parts of this function.

I can easily assert that logout() returns a function, but should I then execute that function and test it as well, and so on down the chain? If this isn't the right place for this, I'll drop it on Stack or somewhere where it belongs :)

Thanks so much

export compatible with CommonJS proposal

Hi,

first of all, thanks for your amazing work, you are helping a lot of people to develop the right way.

May I propose to use this kind of export here

export default module.exports = thunk;

I need to bundle dispatches for performance reasons

Basically, I'd like to beable to create a fake store that I can dispatch multiple actions to, change the fake state completely, and then send the fake store state to the real state. I need to do this because my react state is rendering whenever the state changes, which can be multiple times in a single thunk. This is leading to inefficiencies that I would like to resolve.

Thanks

Any examples for thunk middleware dispatching

Do we know about any real-world examples of testing async action creators?
I struggle to test creators like this:

function add(entity) {
  return dispatch => {
    dispatch({
     type: ADD,
    payload: entity
   })
  }
}

I looked at test here, but it gave me no clue.
Do I have to mock dispatch function or something?

getState and impurity

Why do we need to pass getState function instead of directly pass current state? Since that our actions becomes impure.

action updates devtools store properly but doesn't re-render with the correct state

so on my component I call this dispatch(actions.createExercise(planId))

which calls this action creator

export function createExercise(id) {
  return dispatch => {
    console.log('createExercise')
    const exerciseId = uuid();

    dispatch({
        type: 'CREATE_EXERCISE',
        id: exerciseId,
        exercise: {
          title: 'CREATE_EXERCISE',
          id: exerciseId
        }
      });

    return function(){
      dispatch({
          type: 'ADD_EXERCISE_TO_PLAN',
          id,
          exerciseId
        });
    }
  };
} 

and this are the reducers (only pasted the relevant parts of the code)

const plans = (state = {}, action) => {
  switch (action.type) {
  case 'ADD_EXERCISE_TO_PLAN':
    console.log(action.type)
    return {
      ...state,
      [action.id]: {
        ...state[action.id],
        exercises: [
          ...state[action.id].exercises,
          ...action.exerciseId
        ]
      }
    };  

}


const exercises = (state = {}, action) =>  {
  switch (action.type) { 

  case 'CREATE_EXERCISE':
    return {
      ...state,
      [action.id]: {
        ...action.exercise
      }
    }; 

}

As you can see on the screenshot below the actions were properly called, but the state wasn't properly updated on the component. The printed state (which was printed on the render method) doesn't contain the updated state, neither the exercise was added to the entities object nor the exerciseId was added to the exercises array on the Plan object

image

but if you see on the dev tools, both objects are correct... Thanks in advance, any help is appreciated

image

image

return promise after action creator with thunk

Hi all,

I think I take the wrong way to manage this issue so I ask for advise.
Before mounting a component, I would like to fetch data and then make the component visible.

My action creator is simple :

function loadFoo(fooId) {
  return dispatch => {
    dispatch(loadFooRequest());

    let query = new Parse.Query('Foo');

    query.get(fooId)
    .then((response) => {
      const json = response.toJSON();
      return dispatch(loadFooSuccess(json));

    }, (error) => dispatch(loadFooError(error)))
  }
}

and in my component I just do that :

ComponentDidMount() {
    this.props.dispatch(loadFoo(this.props.params.fooId));
    this.props.dispatch(showPane());
}

My issue is that the Pane will be shown before the data gets loaded.

I would like to do something like :

ComponentDidMount() {
    this.props.dispatch(loadFoo(this.props.params.fooId)).then(() => {
        this.props.dispatch(showPane());
    });
}

What is the right way to manage this kind of thing ?

Thanks

Pause Component Rendering Till Data Fetch Completes

Hi there,

I've been struggling with this problem for several weeks now. I'm finally throwing in the towel and asking for help on this because I'm clearly not doing something right. I have a React.js app that is using redux and redux-thunk. I'm simply trying to get my Component Container to initiate the loading of data, but not render until the data comes back from the fetch request. Seems simple enough I know. Here is what I've done:

Container Component

'use strict';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchActivePlayer } from '../actions/index';
import PlayerDetails from '../components/players/player-detail';
import Spinner from '../components/common/spinner/index';
import store from '../store';

export default class PlayerDetailContainer extends Component {
    constructor(props) {
        super(props);
    }

    componentWillMount() {
        this.props.fetchActivePlayer(this.props.params.player_slug)
    }

    render() {
        if (!this.props.activePlayer.activePlayer) {
            return (
                <Spinner text="Loading..." style="fa fa-spinner fa-spin" />
            );
        }

        return (
            <PlayerDetails 
                player={ this.props.activePlayer.activePlayer } 
            />
        );
    }
}

function mapStateToProps(state) {
    return {
        activePlayer: state.activePlayer
    }
}
export default connect(mapStateToProps, { fetchActivePlayer })(PlayerDetailContainer);

Action Creator

export function fetchActivePlayer(slug) {
    return (dispatch, getState) => {
        return axios.get(`${ROOT_URL}/players/${slug}`)
        .then(response => {
            dispatch({
                type: FETCH_ACTIVE_PLAYER,
                payload: response
            })
        })
        .catch(err => {
            console.error("Failure: ", err);
        });    
    };
}

Store

'use strict';
import React from 'react';
import { browserHistory } from 'react-router';
import { createStore, applyMiddleware } from 'redux';
import { routerMiddleware } from 'react-router-redux';
import thunk from 'redux-thunk';
import promise from 'redux-promise';
import reducers from './components/reducers/index';

const createStoreWithMiddleware = applyMiddleware(
    thunk,
    promise,
    routerMiddleware(browserHistory)
) (createStore);
export default createStoreWithMiddleware(reducers);

Routes

export default (
<Route path="/" component={ App }>
        <IndexRoute component={ HomePage } />
        <Route path="players/:player_slug" component={ PlayerContainer } />
        <Route path="/:player_slug" component={ PlayerContainer } />
    </Route>
);

Here are the versions I'm using for everything:
react = 0.14.7
react-redux = 4.4.1
redux-thunk = 0.5.3

When I run this, I don't receive any errors but it's clear that my action creator is firing but my component container continues instead of waiting for the creator to finish. Like I said, I'm sure I must be missing something really simple but I can't seem to figure out what that is.

Thank you in advance. Any help would be greatly appreciated.

UMD Dist build?

Hey @gaearon,

I'm trying to add redux-thunk to the jsdelivr CDN, would it be possible to add a minified UMD build as part of the npm package? Similar to how redux does it. e.g. dist/redux.min.js

-- Arron

Upgrading to NPM 3.x results throws `UNMET PEER DEPENDENCY`

This can be reproduced locally with the following:

$ npm --version
3.3.9
$ cd path/to/app
$ rm -rf ./node_modules
$ npm cache clean
$ npm install
[...]
├─┬ [email protected] 
│ └─┬ [email protected] 
│   └─┬ [email protected] 
│     ├── [email protected] 
│     ├── [email protected] 
│     └── [email protected] 
├─┬ [email protected] 
│ ├── [email protected] 
│ └─┬ [email protected] 
│   └── [email protected] 
├── UNMET PEER DEPENDENCY redux@^2.0.0 || ^3.0.0
└── [email protected] 

.babelrc should not be in npm repo

I think babelrc is being published in npm which causes react-native app's to crash! It has been fixed in react-redux and redux. However this bug still exists in this module.

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

Is it a correct use-case for thunk-middleware if the actions payload depends on current store state?

We stumbled about this, while upgrading to the new react-redux 0.9.0, in which the Connector component was replaced with the connect higher order function.

Given the situation that the result of mapStateToProps is dependent on the actual props like this:

function mapStateToProps( state, ownProps) {
   return {
      field: ownProps.selectors.map( selector => selector(state) )
   };
}

you will end up with a new selected state even if the memoized selector functions would return the same objects as the resulting array of the map-function is a new object.

We where thinking about resolving this issue, through the following strategies:

  1. Create a compound Selector and pass it as a single property
    This selector would only depend on the passed state of the mapStateToProps function and be memoized.
    Thus it would return a === equal result for the same state, which would lead to a shallow equally props object but would have to also process the result later like:
function mapStateToProps( state, ownProps) {
   return {
      selectedActionArguments: ownProps.compoundSelector(state)
   };
}
function mapDispatchToProps( dispatch, ownProps ) {
   return bindActionCreators({
      updateAction: ownProps.updateAction
   }, dispatch );
}
function mergeProps( stateProps, dispatchProps, ownProps ) {
   return {
      update: dispatchProps.updateAction.bind( undefined, stateProps.selectedActionArguments )
   }
}

Wow it even feels wrong describing it, sorry.

  1. Use Thunk-Middleware to select action parameters from the store in the moment of dispatching.
    This would reduce the function descriptions to a single mapDispatchToProps function like
function mapDispatchToProps( dispatch, ownProps ) {
  return bindActionCreators({
     update: ownProps.updateAction
   }, dispatch );
}

Whereas the updateAction property would be an action creator like:

function createUpdateAction() {
   return function dispatchConcreteAction( dispatch, getState ) {
     let state = getState();
     let currentActionParams = actionParamSelectors.map( selector => selector(state) );
     dispatch( actualActionCreator( ...currentActionParams ) );
   }
}

Wa are not 100% sure if the second approach is a correct use-case for the thunk-middleware.

If so we can provide a well formulated example for the Readme.

Dispatching multiple async actions wipes state when they resolve

I've got two async actions, both of them trigger actions when they resolve which cause two reducers to update their state as a result. These reducers are merged via combineReducers.

I've noticed something strange where the latter action to resolve completely reverts any changes to state that the former action resolves, as if it took an earlier copy of the store's state and made that be the canonical state.

I can't think what I could be doing wrong as my code looks pretty much identical to all of the redux-thunk examples I've found. Is there anything special I should be doing when triggering multiple async actions?

Getting error with TypeScript...

Hello,
I am getting:

capture

when applying:
import thunkMiddleware from "redux-thunk"
let createStoreWithMiddleware = applyMiddleware(thunkMiddleware)(createStore);

any known issues?

regards

Sean

Why would you write an action creator that performs dispatch?

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

An "action creator"—an interface, or concept, defined entirely in English prose—is a function that returns actions: objects that have a key "type".

Now, in this repository, this interface is being bent to return a function with some specific signature that furthermore performs dispatch. Such a returned function is no longer an "action" so the function that returns such a function is not an action creator; not even in the sense that a thunk is the functional representation of some expression, because:

action:

{ type: SOMETHING }

action-thunk:

() => { type: SOMETHING }

I am writing this principally because I think Redux is great but the Redux docs and ecosystem have way too many things like "action creator" that are not actually part of the Redux API. These things seem to be some attempt to create a set of community-understood concepts related to Redux, but given that they are not part of the API—an API that is already built on top a dynamic language—they only serve to cloud the whole picture and are amenable to haphazardly abuse via prose by way of Markdown file.

Clarify on dispatch handling..

Okay, I'm just curious if dispatch(null) would work without actually running any resolvers?

What I'm wanting to do, is something like...

dispatch(getArticleHeader(someId));
...
dispatch(getArticleHeader(someId));

where getArticleHeader(someId) will immediately return {type:'GOT_ARTICLE_HEADERS',headers:[{id:...}]} if it has the data locally, otherwise return null, but add the id to a queue, that will be rollup several id's into a single request to the remote service, then dispatching the joint result.

In this way, I can render results, but have loading status for any id's that don't yet have their details ready.

Accessing store in thunk

Not exactly sure where to put this issue, also I possibly have missed the correct pattern to do what I need.

The scenario is I have reducers/action creators for different screens in my application. I then have a reducer/action creator for application context. This application you can have multiple accounts accessible at the same time, but only one selected.

At the screen level, I want to re-initialise the screen because a bunch of reference data on each screen is dependent on the context. Inside my INIT_SCREEN action creator I want to subscribe to changes in the store, then see if the account context has changed. So I have a cross state tree dependency.

What I want is:

export function initScreen() {
  return (dispatch, getState, store) => {
    let currentAccount = store.getState().context.account
    let sub = store.subscribe(() => {
      if (store.getState().context.account !== currentAccount) {
        sub()
        dispatch(initScreen)
      }
    })
    dispatch({type: INIT_SCREEN})
    // rest of screen init
  }
}

Well, that is what I think I want. Suggestions on a better way to solve this is welcome.

Having issues calling applyMiddleWare

Hi there:

I am having issues when creating a store with redux-thunk as middleware.

Here's the error message:

ERROR in ./web/static/js/index.js
Module build failed: SyntaxError: /Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/web/static/js/index.js: Unexpected token (17:34)
15 | combineReducers({
16 | rootReducer,
17 | applyMiddleware(...ReduxThunk),
| ^
18 | routing: routerReducer
19 | })
20 | )
at Parser.pp.raise (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/location.js:22:13)
at Parser.pp.unexpected (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/util.js:89:8)
at Parser.pp.expect (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/util.js:83:33)
at Parser.pp.parseBlock (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/statement.js:509:8)
at Parser.pp.parseFunctionBody (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:913:22)
at Parser.parseFunctionBody (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/plugins/flow.js:17:20)
at Parser.pp.parseMethod (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:882:8)
at Parser.pp.parseObjPropValue (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:799:10)
at Parser.parseObjPropValue (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/plugins/flow.js:298:13)
at Parser.pp.parseObj (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:777:10)
at Parser.pp.parseExprAtom (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:486:19)
at Parser.parseExprAtom (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/plugins/jsx/index.js:18:22)
at Parser.pp.parseExprSubscripts (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:272:19)
at Parser.pp.parseMaybeUnary (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:252:19)
at Parser.pp.parseExprOps (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:183:19)
at Parser.pp.parseMaybeConditional (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:165:19)
at Parser.pp.parseMaybeAssign (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:128:19)
at Parser.pp.parseExprListItem (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:1032:16)
at Parser.parseExprListItem (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/plugins/flow.js:215:24)
at Parser.pp.parseCallExpressionArguments (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:348:20)
at Parser.pp.parseSubscripts (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:311:31)
at Parser.pp.parseExprSubscripts (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:282:15)
at Parser.pp.parseMaybeUnary (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:252:19)
at Parser.pp.parseExprOps (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:183:19)
at Parser.pp.parseMaybeConditional (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:165:19)
at Parser.pp.parseMaybeAssign (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:128:19)
at Parser.pp.parseExprListItem (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:1032:16)
at Parser.parseExprListItem (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/plugins/flow.js:215:24)
at Parser.pp.parseCallExpressionArguments (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:348:20)
at Parser.pp.parseSubscripts (/Users/osayame/Dropbox/osayame/Work/Luma/repos/luma-command-center/node_modules/babylon/lib/parser/expression.js:311:31)
@ multi main

Here's the code in question:

import 'babel-core/register';
import ReactDOM from 'react-dom';
import React from 'react';
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { Router, Route, browserHistory } from 'react-router';
import { Provider } from 'react-redux';
var ReduxThunk = require('redux-thunk').default
import { syncHistoryWithStore, routerReducer } from 'react-router-redux';
import rootReducer from './reducers/index';
import routes from './routes';
import "../css/index.css";
const store = createStore(
combineReducers({
rootReducer,
applyMiddleware(...ReduxThunk),
routing: routerReducer
})
)
const history = syncHistoryWithStore(browserHistory, store)
const rootElement = document.getElementById('root');
ReactDOM.render(


,
document.getElementById('root')
);

Expected identifier error in IE8

At line 6:

exports.default = thunkMiddleware;

default is a reserved keyword in IE8 and it throws an errror when dot notation is used. it does work when bracket notation is used:

exports['default'] = thunkMiddleware;

I think this is a bug in the upstream babel-plugin-add-module-exports, but wanted to show it here in case people are looking here first.

Call Dispatch Multiple Times

Is this ok?

export function getSpecAcct(aId)
{
  return dispatch => {
    ResponsiveCtrl.getSpecAcct(aId,function(r, e) {
      dispatch(showAccount(r));
      dispatch(updatePath('/comppage'));
    });
  }
}

Why a separate repo?

Just a small question... Why does this small middleware have its own repo? Wouldn't it make more sense for it to live in the redux repo too?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.