Search code examples
react-nativereduxredux-thunkreact-native-contacts

In a Redux's Action, Calling a Function with Callbacks (Using async/await with React-Native-Contacts)


I am developing a mobile app, which uses React-Native, Redux and React-Native-Contacts.

In an action creator, I am trying to call a function (from React-Native-Contacts), which has callbacks (rather than promises). Following is my code.

I want the action "acContactImport" to wait for the helper function "fContactImport" to finish before proceeding to the "dispatch" statement. It does not wait for it. How can I make it wait for it?

// Action Creator: 
import Contacts from 'react-native-contacts';
import { PermissionsAndroid } from 'react-native'; 

export const acContactImport = (userID) => {
    return async (dispatch) => {
      let contactList = [];
      try {
          // The following statement should be executed asynchronously. 
          // However, it is not. How can I make it asynchronous? 
          contactList = await fContactImport();

          dispatch({
            type: CONTACT_IMPORT,
            payload: { contactList: contactList },

          });
      } 
      catch (err) {
        console.log("acContactImport - catch: ", err);
      }
    }; 
}; 

// Helper Function 1
export const fContactImport = async () => {
  let contactList = [];
    if (Platform.OS === "android") {
        PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.READ_CONTACTS, {
            title: "Contacts",
            message: "This app would like to view your contacts."
        })
        .then(() => {
            contactList = _loadContacts();
        });
    } else {
        contactList = _loadContacts();
    } 
}

// Helper Function 2
export const _loadContacts = () => {
    Contacts.getAll((err, data2) => {
      if (err) {
        return []; 
      }
      else {
        let candidates = [];
        for (let i = 0; i < data2.length; i++) {
            let candidateObject = { name: candidateRecord.givenName + " " + candidateRecord.middleName + " " + candidateRecord.familyName };
            candidates.push(candidateObject);
        }
        return contactList; 
      }
  });
}

Solution

  • Apparently, the problem is NOT in the action creator, but in the helper functions, which do not support the new style of promises (async/wait). So, here is the solution...

    // Action Creator: 
    // No changes are required. Original code is good. 
    
    // Helper Function 1
    export const fContactImport = async () => {
      let contactList = [];
      if (Platform.OS === "android") {
        try {
          const granted = await PermissionsAndroid.request(
            PermissionsAndroid.PERMISSIONS.READ_CONTACTS,
            {
                title: "Contacts",
                message: "This app would like to view your contacts."
            },
          );
    
          if (granted === PermissionsAndroid.RESULTS.GRANTED) {
            contactList = await _loadContacts();
          } else {
            console.log('Contacts access denied');
          } 
    
        } catch (err) {
          console.warn(err);
        } 
      } else {
        contactList = await _loadContacts();
      }
      return contactList;
    }
    
    // Helper Function 2
    export const _loadContacts = () => {
      return new Promise((resolve, reject) => {
        Contacts.getAll((err, data2) => {
          if (err) {
            reject([]);
          }
          else {
            let candidates = [];
            for (let i = 0; i < data2.length; i++) {
                let candidateObject = { name: candidateRecord.givenName + " " + candidateRecord.middleName + " " + candidateRecord.familyName };
                candidates.push(candidateObject);
            } 
            resolve(candidates);
          }
        });
      });
    }