1

I'm making web site using react based on Firebase. Recently, I met some problem about getting url of storage. Below is my codes.

(state, action) => {
  const snapshot = action.payload;
  const list = [];

  snapshot.forEach((child) => {
    list.push({
      key: child.key,
      user_bg_url: child.val().user_bg_url,
      user_hp: child.val().user_hp,
      user_id: child.val().user_id,
      user_img_url: child.val().user_img_url,
      user_login_yn: child.val().user_login_yn,
      user_msg_block: child.val().user_msg_block,
      user_token: child.val().user_token,
    });
  });

  list.forEach(async (user) => {
    await storage.getUserImage(user.user_img_url).then((url) => {
      user.user_img_url = url;
    });
  })

  return state.setIn(['users', 'list'], list);
}

getUserImage: (gs_url) => {
  return storage.refFromURL(gs_url).getDownloadURL();
},

I want to return value after work of 'list.forEach'. But it just return blank array before completion of 'list.forEach'.

AL.
  • 36,815
  • 10
  • 142
  • 281
oh3vci
  • 72
  • 1
  • 7

1 Answers1

2

You're correct that return is getting called before your forEach completes, so you'll need to return a promise. Using Promise.all() and map would work here.

return Promise.all(list.map(async (user) => {
  await storage.getUserImage(user.user_img_url).then((url) => {
    user.user_img_url = url;
  });
})).then(() => {
  return state.setIn(['users', 'list'], list);
});

Inspired by this answer.

Community
  • 1
  • 1
Jeff
  • 2,425
  • 1
  • 18
  • 43
  • Answer thanks, Jeff. But this answer did not return value I want. – oh3vci Apr 12 '17 at 19:10
  • Because I used specific function getting state for convenience about then() of promise. So, if return value is function, it is not given to specific function. So the origin code return just state. – oh3vci Apr 12 '17 at 19:16
  • Looks like you're using redux here. Usually reducers like your function don't do anything asynchronous because they need to return the state object. Look into using asynchronous actions (http://redux.js.org/docs/advanced/AsyncActions.html) to do the asynchronous stuff, and only call the reducers when you have the results you need. – Jeff Apr 12 '17 at 22:27
  • 1
    The function I mentioned was using redux-promise-middleware... However, I solved this problem as setting state of the component that it is used from the result excepted 'list.forEach'. – oh3vci Apr 13 '17 at 11:24