Search code examples
javascriptfirebasereact-reduxredux-thunk

Javascript, Redux thunk, synchronous / nested promises


I have a direct messaging application. All the data is stored in Firebase. Each chat contains an array of user IDs.

I use the following function to get all chats from componentDidMount():

return dispatch => new Promise(resolve => FirebaseRef.child('chats')
    .on('value', snapshot => resolve(dispatch({
      type: 'CHATS_REPLACE',
      data: snapshot.val() || [],
    })))).catch(e => console.log(e));

Which goes through:

chatReducer(state = initialState, action) {
  case 'CHATS_REPLACE': {
      let chats = [];

      if (action.data && typeof action.data === 'object') {
        chats = Object.values(action.data).map(item => ({
          id: item.id,
          title: item.title,
          authorizedUsers: Object.values(item.authorizedUsers).map(user => ({
            id: user.id,
            // Somedata: fetchUserData(user.id)
            // -> pretty sure it can't be done here <-
          })),
        }));      
      }

      return {
        ...state,
        error: null,
        loading: false,
        chats,
      };

How would I go about fetching more data of every user inside each chat from Firebase at users/:uid?


Solution

  • I don't know what is the use case of this. It would be great if you can share, like how much information about the user you want to use. If its small data, why don't you add it in same API Only. You can pass the users data in the same object with user id as keys, and use the same keys inside your nested data like (only if user data is small or you know API data is always limited like because of pagination or page size. :

    {
        posts : [
         {
           title : 'abc'
           authorizedUsers : ['1a', '2b', '3c']
         }, ....
         ],
         users : {
          '1a' : {
              name : 'john doe',
              profileImage : 'https://some.sample.link',
            },
           '2b' : {
              name : 'bob marshal',
              profileImage : 'https://some.sample.link2',
            }
         }
    }
    

    If data is huge or cannot be added in the API ( because API is owned by 3rd party), then only place you can put you code is, instead of just dispatching the actions after the response is recieved, loop over the response in your service only, make async calls to get all "Unique users" only, append that data to the data you recieved from the previous api call, and then dispatch the action with the complete data to the store. It might not be the best way, as everything will have to stall i.e. even the data recieved in 1st api also will stall(not updated on screen) till all the users data is fetched. But best solution can only be given once we know more details about the use case. Like maybe lazy fetching the users data as end user scrolls the screen and may see a particular post Or fetching the user details once you start rendering your data from 1st API call like making a component for showing user associate with a post and in its componentDidMount, you pass the userIds as props from top component which might be "article/post/blog" component and it fetched the data at the time when it is actually rendering that "article/blog/post".

    Hope this helps.