4
votes

I'm having this issue when I'm trying to invoke a callback after the promise resolves (using .then) It turns out that this gives my const request some kind of different promise that reducer returns as undefined:

action:

   export function lookup(company, callback) {
      const id = company.textfield;
      const url = `${ROOT_URL}${id}`;

      const request = axios.get(url)
       .then(() => callback())

      return {
        type: LOOK_UP,
        payload: request,
        meta: id
     };
 }

reducer:

import { LOOK_UP } from '../actions/index';

export default function(state = {}, action) {
    switch (action.type) {
        case LOOK_UP:
            const data = action.payload.data;
            const id = action.meta;

            if (data.Success === true) {
                return { ...state, [id]: data.CompanyInformation };
            } else {
                return state;
            }
    }
    return state;
}

As you can see I pass the data from API that axios get to my reducer. After this I set the state and I need to invoke that callback that is in 'actions' (it creates then another action call inside component). Unfortunatelly, I got error that in reducer const data = action.payload.data is undefined.

When I don't use this callback everything works fine, but the case is that I neet to invoke that callback only after this reducer returns new state.

2
Any progress? Have you had time to try my suggestions?jonahe
I see now, this time the callback is invoked, but I think that the problem here is that it's fired too soon. I mean, this callback relays on the new state returned from reducer with this LOOK_UP action. I have to make another function that will fire up after this state is changed and not only when the promise is resolved.Mateusz Szymajda
Does the callback really rely on the new state, or just the return from request = axios.get(url)? If it's only that the callback need the response as an argument, then you can simply use my first suggestion but with callback(dataFromRequest); Or callback(dataFromRequest.data); or what ever info you are interested in. You can also include the if-statement. etc. and do Promise.reject( ) if dataFromRequest.data.SUCESS !== true .jonahe
What library are you using for the promises? You have the tag redux-promise. Is is this one? github.com/acdlite/redux-promise The examples are so few there that it's hard to see how it's supposed to be used. Is it redux-promise that adds the .Success ?jonahe
Yes, I'm using redux-promise, but the .Success comes form API (this api returns object with data/null and Success true/false). So I think the most reasonable thing to do is to use that callback with dataFromRequest that comes back from request in this case. But I guess for my reducer I still need to return the part with type: LOOK_UP, payload: request etc?Mateusz Szymajda

2 Answers

3
votes

Best way to use another callback in action need to replace you middleware "redux-promise" to "redux-thunk"

import ReduxThunk from 'redux-thunk'
const store = createStore(applyMiddleware(ReduxThunk));

action:

export function lookup(company, callback) {
  const id = company.textfield;
  const url = `${ROOT_URL}${id}`;


  return function(dispatch) { 
        axios.get(url)
       .then((res) => {
            dispatch({ type: LOOK_UP, payload: res,  meta: id });
            callback();
         )
      };
 }

reducers:

import { LOOK_UP } from '../actions/index';

export default function(state = {}, action) {
    switch (action.type) {
        case LOOK_UP:
            const data = action.payload.data;
            const id = action.meta;

            if (data.Success === true) {
                return { ...state, [id]: data.CompanyInformation };
            } else {
                return state;
            }
    }
    return state;

}

2
votes

request is equals to this whole statement:

const request = axios.get(url)
   .then(() => callback())

So if callback() doesn't return something, then the promise will resolve to nothing. I assume you are fetching some data with this call, so you need to pass that data on, or else your reducer will never get it. Like so:

const request = axios.get(url)
   .then((dataFromRequest) => { 
     callback(); 
     return dataFromRequest; 
});

Or you can separate the two and write something like:

const request = axios.get(url);
request.then(() => callback());

return {
    type: LOOK_UP,
    payload: request,
    meta: id
 };

Compare the promises in the snippet below:

const promisedData = () => Promise.resolve(42);

promisedData()
  .then(data => console.log('Resolved data is ', data));


const promisedTrasformedData = () => 
   Promise.resolve(700)
   .then(data => data - 34);
   
   
promisedTrasformedData()
  .then(transformedData => console.log('Transformed data is ', transformedData));
  
  

const promisedAndLostData = () => 
  Promise.resolve(42)
 .then(data => returnNoting())

function returnNoting() { };

promisedAndLostData()
 .then(lostData => console.log('Lost data: ', lostData))