Amrita Stha
Amrita Stha

Reputation: 3337

Make two actions work simultaneously - react native and redux

I've a button that sends two actions. First one adds the user infos in an array if certain condition is met and 2nd one sends the data to the server. Since both actions are in onPress function, the 2nd action doesn't wait till it adds up the infos in an array. Henceforth, it always sends empty array. How can I make this two actions work simultaneously.

<TouchableOpacity
    onPress={() => {
      if (true) {
        this.props.AuthUserInfoGet(SignUpName, SignUpDesignation, SignUpEmail, SignUpMobileNo); //calculates & return SignUpUsers
      }
      this.props.SignUpCheck(SignUpUsers); //upload SignUpUsers but SignUpCheck is always empty here
    }}
>
      <Text>Upload</Text>
</TouchableOpacity>

const mapStateToProps = (state) => {
  const {SignUpUsers} = state.Auth;
  //it gives an empty array first and then expected value
  console.log('SignUpUsersz', SignUpUsers);

  return {SignUpUsers};
};

Action:

export const AuthUserInfoGet = (SignUpName, SignUpDesignation, SignUpEmail, SignUpMobileNo) => {
  return ({
    type: SIGN_UP_USER_INFO_GET,
    payloadName: SignUpName,
    payloadDesignation: SignUpDesignation,
    payloadEmail: SignUpEmail,
    payloadMobile: SignUpMobileNo,
  });
}

export const SignUpCheck = (userInfo) => {
    console.log('userInfo', userInfo); // userInfo is always empty
}

Reducer:

const INITIAL_STATE = { SignUpUsers: [] }

case SIGN_UP_USER_INFO_GET:
  return { ...state, SignUpUsers: [...state.SignUpUsers, {member_name: actions.payloadName, designation: actions.payloadDesignation,
    email: actions.payloadEmail, mobile_number: actions.payloadMobile}] };

Upvotes: 0

Views: 148

Answers (2)

Victor Cordos
Victor Cordos

Reputation: 3

For that I would suggest you take a look at redux-thunk middleware.

Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods dispatch and getState as parameters.

And based on your example, the code will end up like this:

<TouchableOpacity 
  onPress={() => this.props.uploadSignUpUsers(SignUpName, SignUpDesignation, SignUpEmail, SignUpMobileNo)}>

  <Text>Upload</Text>
</TouchableOpacity>

const mapStateToProps = (state) => {
  const { Auth: { SignUpUsers } } = state;

  return { SignUpUsers };
}

Actions:

export const SIGN_UP_GET_USER_INFO_SUCCESS = "SIGN_UP_GET_USER_INFO_SUCCESS";
export const SIGN_UP_UPLOAD_SUCCESS = "SIGN_UP_UPLOAD_SUCCESS";

export const uploadSignUpUsers = (SignUpName, SignUpDesignation, SignUpEmail, SignUpMobileNo) => {
   return async (dispatch, getState) => {

       // here you can make the api call or any other async calculations
       const { data: AuthUserInfo, error } = await api.post(SignUpName, SignUpDesignation, SignUpEmail, SignUpMobileNo);

       dispatch({
           type: SIGN_UP_GET_USER_INFO_SUCCESS,
           payloadName: AuthUserInfo.SignUpName,
           payloadDesignation: AuthUserInfo.SignUpDesignation,
           payloadEmail: AuthUserInfo.SignUpEmail,
           payloadMobile: AuthUserInfo.SignUpMobileNo,
       });

       const { Auth: { SignUpUsers } } = getState()

       // and now you can upload your SignUpUsers
       const { data: uploadData, error } = await.api.post(SignUpUsers)

       dispatch({
           type: SIGN_UP_UPLOAD_SUCCESS,
           ...uploadData // spread upload data to make it available in reducers 
       });
    }
}

Reducer:

const INITIAL_STATE = { SignUpUsers: [] }

case SIGN_UP_GET_USER_INFO_SUCCESS: {
    const { payloadName, payloadDesignation, payloadEmail, payloadMobile } = actions
    return { 
        ...state, 
        SignUpUsers: [ ...state.SignUpUsers, { 
            member_name: payloadName, 
            designation: payloadDesignation, 
            email: payloadEmail, 
            mobile_number: payloadMobile 
        }] 
    }
}

Upvotes: 0

Cat_Enthusiast
Cat_Enthusiast

Reputation: 15688

Given your current Redux-structure, I think what makes the most sense to use the componentDidUpdate life-cycle method.

The main reason is because your component ultimately needs to get updated data from Redux via props and needs to re-render. When you execute the first action, that user-data coming from the API is not immediately available in the current call-stack, so you'll always be passing an empty array (given your initial value of SignUpUsers: [])

Note that most React-Redux flows follow this path:

User-Event -> Action-Creator -> API (Data) -> Redux -> Component

Your click-event is at step 1 and triggers this action: this.props.AuthUserInfoGet(...args)

But React/Redux needs to go through that entire flow before you can use the new data.

This is where the componentDidUpdate() event comes in-handy because you can write logic when the component is re-rendered by new props or state.

Something like this would totally work:

componentDidUpdate(prevProps){
   if(prevProps.SignUpUsers.length !== this.props.SignUpUsers.length){
      //execute action
      this.props.SignUpCheck(this.props.SignUpUsers)
   }
}

Upvotes: 2

Related Questions