javascript - Put function that returns promise in redux state - Stack Overflow

I'll explain why I want to do this later. Here is the problem. I have a function that returns a p

I'll explain why I want to do this later. Here is the problem. I have a function that returns a promise like below:

const testFunc = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() >  0.5) {
        resolve('succeeded');
      } else {
        reject('failed');
      }
    }, 1000);
  });
};

As expected, I can invoke it like this just fine:

testFunc()
  .then((result) => console.log(result)) // 'succeeded'
  .catch((error) => console.log(error)); // 'failed'

Or assign it to a variable and call it like this

const testFuncVar = testFunc;
testFuncVar()
  .then((result) => console.log(result)) // 'succeeded'
  .catch((error) => console.log(error)); // 'failed'

These are all expected. However, once I put the function in redux state, then invoke it from there, it doesn't work anymore. Here is what I did (grossly simplified).

const initialState = {testFunc: testFunc};
// redux reducer, action creator, etc.
...
...
// somewhere later. Here I'm using redux-thunk to access redux state
function testFunInState() {
  return (dispatch, getState) => {
    const {testFunc} = getState();
    // this is not working
    testFunc()
      .then((result) => console.log(result))
      .catch((error) => console.log(error));
  };
}

The error I got was _promise2 is not defined. Note that the variable name _promise2 should be from babel transpiler. If I console.log(state.testFunc) or console.log(testFunc), I got:

testFunc() {
  return new _promise2.default(function (resolve, reject) {
    if (Math.random() > 0.5) {
      resolve('succeeded');
    } else {
      reject('failed');
    }
  });
}

So somehow the Promise object got lost whenever the function is put in redux state?

But I did find a workaround. If I change the function to

const testFunc = (resolve, reject) => {
  setTimeout(() => {
    if (Math.random() >  0.5) {
      resolve('succeeded');
    } else {
      reject('failed');
    }
  }, 1000);
};

And call it with resolve and reject passed in as parameters, then I'm good.

// this works
new Promise((resolve, reject) => state.testFunc(resolve, reject))
  .then((result) => console.log(result))
  .catch((error) => console.log(error));

I'm wondering why a function that returns promise doesn't work once it's put in redux store, but one without returning promise works?

Now onto why I want to do it this way. What I'm trying to achieve is to have a job queue that periodically dispatch some async actions, and depending on the result (resolve or reject), does something else (like retry, or send out notification). I want to dynamically add/remove jobs to and from the queue, therefore it's hard to have a reducer that can handle all possible actions. It feels like this is a reasonable way to approach it. I'm open to suggestions.

I'll explain why I want to do this later. Here is the problem. I have a function that returns a promise like below:

const testFunc = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() >  0.5) {
        resolve('succeeded');
      } else {
        reject('failed');
      }
    }, 1000);
  });
};

As expected, I can invoke it like this just fine:

testFunc()
  .then((result) => console.log(result)) // 'succeeded'
  .catch((error) => console.log(error)); // 'failed'

Or assign it to a variable and call it like this

const testFuncVar = testFunc;
testFuncVar()
  .then((result) => console.log(result)) // 'succeeded'
  .catch((error) => console.log(error)); // 'failed'

These are all expected. However, once I put the function in redux state, then invoke it from there, it doesn't work anymore. Here is what I did (grossly simplified).

const initialState = {testFunc: testFunc};
// redux reducer, action creator, etc.
...
...
// somewhere later. Here I'm using redux-thunk to access redux state
function testFunInState() {
  return (dispatch, getState) => {
    const {testFunc} = getState();
    // this is not working
    testFunc()
      .then((result) => console.log(result))
      .catch((error) => console.log(error));
  };
}

The error I got was _promise2 is not defined. Note that the variable name _promise2 should be from babel transpiler. If I console.log(state.testFunc) or console.log(testFunc), I got:

testFunc() {
  return new _promise2.default(function (resolve, reject) {
    if (Math.random() > 0.5) {
      resolve('succeeded');
    } else {
      reject('failed');
    }
  });
}

So somehow the Promise object got lost whenever the function is put in redux state?

But I did find a workaround. If I change the function to

const testFunc = (resolve, reject) => {
  setTimeout(() => {
    if (Math.random() >  0.5) {
      resolve('succeeded');
    } else {
      reject('failed');
    }
  }, 1000);
};

And call it with resolve and reject passed in as parameters, then I'm good.

// this works
new Promise((resolve, reject) => state.testFunc(resolve, reject))
  .then((result) => console.log(result))
  .catch((error) => console.log(error));

I'm wondering why a function that returns promise doesn't work once it's put in redux store, but one without returning promise works?

Now onto why I want to do it this way. What I'm trying to achieve is to have a job queue that periodically dispatch some async actions, and depending on the result (resolve or reject), does something else (like retry, or send out notification). I want to dynamically add/remove jobs to and from the queue, therefore it's hard to have a reducer that can handle all possible actions. It feels like this is a reasonable way to approach it. I'm open to suggestions.

Share Improve this question edited Jul 2, 2016 at 22:06 realbug asked Jul 1, 2016 at 21:41 realbugrealbug 4487 silver badges16 bronze badges 5
  • That's confusing, especially the error as there doesn't seem to be a _promise2 ... anything .. in the posted code ? – adeneo Commented Jul 1, 2016 at 21:46
  • 1 I highly suspect the bug you encountered is not shown in this snippet. It doesn't matter what the function returns, you're just storing a reference to it in the store. – AlexG Commented Jul 1, 2016 at 21:46
  • @adeneo _promise2 should be from bable transpiler. I've edited the question to make it more clear. – realbug Commented Jul 1, 2016 at 22:44
  • Post the reducer code where you stamp the promise func on state – lux Commented Jul 2, 2016 at 0:06
  • @lux, I'm using redux-thunk to access testFunc in state. I've made additional edit to the original question. @AlexG, I had the same understanding that what gets returned doesn't matter, as I'm just storing a reference to the function. But somehow whenever I have new Promise in the function, it stops working. – realbug Commented Jul 2, 2016 at 22:08
Add a ment  | 

2 Answers 2

Reset to default 4

With a bit more digging, I finally figured that the problem really has nothing to do with redux or promise. It's simply because they way testFunc getting added to redux state through assignment to initialState object literal. When it's done this way, the binding is lost, hence the _promise2 is undefined error. Actually if I add testFunc to redux state dynamically (e.g. via action creator and reducer), the binding got preserved and everything works just fine. Here is a more detail explanation of the issue https://stackoverflow./a/2702028/4401488.

Just for reference, here is the code for adding testFunc to redux state via reducer

const initialState = {};
// redux reducer
export default function jobReducer(state = initialState, action = {}) {
  switch (action.type) {
    case ADD_JOB:
      return {job: action.job};
    default:
      return state;
  }
}

// action creator
export function addJob(job) {
  return {
    type: ADD_JOB,
    job: job
  };
}
...
// add testFunc to redux state via action creator,
// I'm using redux-thunk here to access dispatch
function addTestFun() {
  return (dispatch) => {
    dispatch(addJob(testFunc));
  };
}
...
// invocation of testFunc. Here I'm using redux-thunk to access redux state
function testFunInState() {
  return (dispatch, getState) => {
    const {testFunc} = getState();
    // Now this is working
    testFunc()
      .then((result) => console.log(result))
      .catch((error) => console.log(error));
  };
}

You need to use middleware with Redux such as Redux Thunk

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

// Note: this API requires redux@>=3.1.0
const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);

Then write your action like so:

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

You could also try using Redux-Promise

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744346900a4569740.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信