Dispatch function seems to run more than one time after I test on stand alone app expo-deeplink

Viewed 325

It sounds so weird to me and I have no idea what's wrong here because everything is fine in a development environment. So the way app works are simple, user sign in, choose it's therapist then pay for it and after successful payment, booking is confirmed, but the problem is booking is being booked exactly 3 times in firebase real-time database no matter what and I don't know why... (in the development area all is fine and it's gonna book just once as the user requested)

here's my code of booking:

const bookingHandler = () => {
    Linking.openURL('http://www.medicalbookingapp.cloudsite.ir/sendPay.php');
  }

  const handler = (e) => handleOpenUrl(e.url);
  useEffect(() => {

    Linking.addEventListener('url', handler)

    return () => {
      Linking.removeEventListener('url', handler);

    }

  });

  const handleOpenUrl = useCallback((url) => {
    const route = url.replace(/.*?:\/\/\w*:\w*\/\W/g, '') // exp://.... --> ''
    const id = route.split('=')[1]

    if (id == 1) {
      handleDispatch();
      toggleModal();
    } else if (id == 0) {
      console.log('purchase failed...');
      toggleModal();
    }
  });

  const handleDispatch = useCallback(() => {
    dispatch(
      BookingActions.addBooking(
        therapistId,
        therapistFirstName,
        therapistLastName,
        selected.title,
        moment(selectedDate).format("YYYY-MMM-DD"),
        selected.slots,
      )
    );

    dispatch(
      doctorActions.updateTherapists(therapistId, selected.slots, selectedDate, selected.title, selectedPlanIndex, selectedTimeIndex)
    );
    setBookingConfirm(true)
  })

booking action:

export const addBooking = (therapistId, therapistFirstName, therapistLastName, sessionTime, sessionDate, slotTaken) => {
  return async (dispatch, getState) => {
    let userId = firebase.auth().currentUser.uid
    
    const confirmDate = moment(new Date()).format("ddd DD MMMM YYYY")

    const response = await fetch(
      `https://mymedicalbooking.firebaseio.com/bookings/${userId}.json`,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          userId,
          therapistId,
          confirmDate,
          therapistFirstName,
          therapistLastName,
          sessionTime,
          sessionDate,
          slotTaken
        })
      }
    );

    if (!response.ok) {
      throw new Error('Something went wrong!');
    }

    const resData = await response.json();
   
    dispatch({
      type: ADD_BOOKING,
      bookingData: {
        userId: userId,
        therapistId: therapistId,
        therapistFirstName: therapistFirstName,
        therapistLastName: therapistLastName,
        sessionTime: sessionTime,
        sessionDate: sessionDate
      }
    });
  };
};

Booking reducer:

const initialState = {
  bookings: [],
  userBookings: []
};

export default (state = initialState, action) => {
  switch (action.type) {
    case ADD_BOOKING:
      const newBooking = new Booking(
        action.bookingData.id,
        action.bookingData.therapistId,
        action.bookingData.therapistFirstName,
        action.bookingData.therapistLastName,
        action.bookingData.bookingdate
      );
      return {
        ...state,
        bookings: state.bookings.concat(newBooking)
      };
    case FETCH_BOOKING:
      const userBookings = action.userBookings;
      return {
        ...state,
        userBookings: userBookings
      };
  }

  return state;
};

also, I use expo, SDK 38, Firebase as a database.

I really need to solve this, please if you have any idea don't hesitate to leave a comment or answer all of them kindly appreciated.

UPDATE:

I commented out all deep linking functionality and test the result, it's all fine. so I think the problem is with the eventListener or how I implemented my deep linking code but I still don't figure out what's wrong with the code that does fine in expo and has a bug in stand-alone.

UPDATE 2

I tried to add dependency array as suggested but still I have same problem..

1 Answers

there is an issue in expo-linking which on the standalone detached android app: event url fires multiple times ISSUE

I just wrapped my handling function in lodash's debounce with 1000ms wait

install lodash like this

yarn add lodash
import _ from 'lodash';

const handleOpenUrl = _.debounce((event) => {
    // here is other logic
  },1000);

here is your code

just add an empty dependency array into useEffect and use useCallback like this

useEffect(() => {
    Linking.addEventListener('url', handleOpenUrl)
    return () => {
      Linking.removeEventListener('url', handleOpenUrl);
    }

  },[]);  //like this []
const handleOpenUrl = _.debounce((url) => {
    const route = url.replace(/.*?:\/\/\w*:\w*\/\W/g, '') // exp://.... --> ''
    const id = route.split('=')[1]

    if (id == 1) {
      handleDispatch();
      toggleModal();
    } else if (id == 0) {
      console.log('purchase failed...');
      toggleModal();
    }
  },1000); //like this []
const handleDispatch = useCallback(() => {
    dispatch(
      BookingActions.addBooking(
        therapistId,
        therapistFirstName,
        therapistLastName,
        selected.title,
        moment(selectedDate).format("YYYY-MMM-DD"),
        selected.slots,
      )
    );

    dispatch(
      doctorActions.updateTherapists(therapistId, selected.slots, selectedDate, selected.title, selectedPlanIndex, selectedTimeIndex)
    );
    setBookingConfirm(true)
  },[selected]) 
Related