0

How do I write these functions so that the dispatch finalizes before the if statements start? Currently, the if statements start console.log()'ing before the dispatch can even save the data.

  const doStuff = () => {
    dispatch(getStuff()); // WAIT FOR ME TO COMPLETE BEFORE MOVING ON!!!
    
    if (stuff) {   //stuff is retreived from global state
      console.log("stuff available") //I WAITED FOR THE DISPATCH!
    }

    if (!stuff) {   //stuff is retreived from global state
      console.log("no stuff") //I WAITED FOR THE DISPATCH!
    }
  };

export const getStuff = () => { \\WAIT FOR ME TO SAVE STUFF!!!
  return (dispatch) => {
      axios.get(`/stuff`).then((response) => {
      dispatch({
        type: SAVE_STUFF_TO_STATE, //stuff is saved to global state
        payload: response.data, //stuff
      });
      })
    } catch (err) {
      console.log("stuff issue")
    }
  };
};
twominds
  • 1,084
  • 5
  • 20

2 Answers2

1

You can return the promise from the function, you can try using https://github.com/reduxjs/redux-thunk

enter code hereexport const getStuff = () => { \\WAIT FOR ME TO SAVE STUFF!!!
 return (dispatch) => {
    axios.get(`/stuff`).then((response) => {
      return Promise.resolve(
         // the actions to be dispatched goes here
      );
    })
  } catch (err) {
     console.log("stuff issue")
  }
 };
};

and wait for it execution,

 const doStuff = () => {
    dispatch(getStuff()).then(()=> { // WAIT FOR ME TO COMPLETE BEFORE MOVING ON!!!

      if (stuff) {   //stuff is retreived from global state
       console.log("stuff available") //I WAITED FOR THE DISPATCH!
      }

      if (!stuff) {   //stuff is retreived from global state
       console.log("no stuff") //I WAITED FOR THE DISPATCH!
      }
   });
 };

In general, if you want to chain certain activities (as per your example) on the dispatch, your action would need to return a Promise

Sasi Kumar M
  • 2,440
  • 1
  • 23
  • 23
  • I tried this before asking this question, but I tried it again for fun, and it doesn't work. I get an error: Cannot read property 'then' of undefined. I read up on this, its because dispatch functions dont return anything, so they cant have a .then(). – twominds Dec 22 '20 at 07:48
  • You need to return the promise from getStuff: **return** axios.get(`/stuff`).then – HMR Dec 22 '20 at 07:54
  • @HMR I just tried adding a return to the axios, Promise, and dispatch individually, neither one worked. The one you specified broke the code by somehow stopping the dispatch function in the promise. The others came up with the same original error. – twominds Dec 22 '20 at 08:06
  • @user67 I've added a working example, if you can't get it to work then please provide a sandbox demonstrating the problem. – HMR Dec 22 '20 at 08:09
  • @HMR ok thanks, I'm currently looking at and understanding your example. – twominds Dec 22 '20 at 08:17
  • @user67. i was under assumption you were using thunk, since you used dispatch on return inside a function. If you haven't, then you might need redux thunk, to enhance your functions to return an action. – Sasi Kumar M Dec 22 '20 at 10:28
  • @SasiKumarM I do have redux-thunk installed in my modules. Im looking at alternative options like saga. It seems that the .then() returns nothing. thanks. – twominds Dec 22 '20 at 11:05
  • i forgot to add a return to the promise. redux thunk would definitely work in this scenario, https://stackoverflow.com/questions/35069212/return-promise-from-store-after-redux-thunk-dispatch – Sasi Kumar M Dec 22 '20 at 11:13
1

Your promise creating function needs to return a promise and your thunk action needs to return that promise:

const { Provider, useDispatch, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;

const initialState = {
  status: 'initial',
};
//action types
const ONE = 'ONE';
const TWO = 'TWO';
//action creators
const later = (value, time = 2000) =>
  new Promise((resolve) =>
    setTimeout(() => resolve(value), time)
  );
const one = () => (dispatch) =>
  //return the promise here
  later()
    .then(() => dispatch({ type: ONE }))
    .then(() => later('the value one resolves with'));
const two = () => ({ type: TWO });
const reducer = (state, { type, payload }) => {
  if (type === ONE) return { ...state, status: 'one' };
  if (type === TWO) return { ...state, status: 'two' };
  return state;
};
//selectors
const selectStatus = (state) => state.status;
//creating store with redux dev tools
const composeEnhancers =
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
  reducer,
  initialState,
  composeEnhancers(
    applyMiddleware(
      ({ dispatch, getState }) => (next) => (action) =>
        //basic thunk implementation
        typeof action === 'function'
          ? action(dispatch, getState)
          : next(action)
    )
  )
);
const App = () => {
  const dispatch = useDispatch();
  React.useEffect(() => {
    one()(dispatch).then((oneResolve) => {
      console.log('one resolved with:', oneResolve);
      dispatch(two());
    });
  }, [dispatch]);
  const status = useSelector(selectStatus);
  return <h1>Status:{status}</h1>;
};

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
<div id="root"></div>
HMR
  • 37,593
  • 24
  • 91
  • 160