useBuyerJourneyIntercept may cause infinity loop

What’s happens

When you call any update api such as useApplyAttributeChange, useApplyShippingAddressChange and useApplyCartLinesChange in useBuyerJourneyIntercept, it case infinity loop.

  const applyAttributeChange = useApplyAttributeChange();

  useBuyerJourneyIntercept(
    ({canBlockProgress}) => {
      return canBlockProgress && address?.countryCode && address.countryCode !== 'CA'
        ? {
            behavior: 'block',
            reason: 'Invalid shipping country',
            errors: [
              {
                message:
                  'Sorry, we can only ship to Canada',
                // Show an error underneath the country code field
                target:
                  '$.cart.deliveryGroups[0].deliveryAddress.countryCode',
              },
              {
                // In addition, show an error at the page level
                message:
                  'Please use a different address.',
              },
            ],
          }
        : {
            behavior: 'allow',
            perform: async () => {
              await applyAttributeChange({....});
            };
          };
    },
  );

Reason

This is currently the intended behavior.
Callback of useBuyerJourneyIntercept will run various timing such as …

  • change order data
  • hover submit button
  • click next button in 3 pages checkout
  • etc…

so that extensions can validate information as it changes.

When you call update api like useApplyAttributeChange in useBuyerJourneyIntercept that case useBuyerJourneyIntercept’s callback again!!

This is why useBuyerJourneyIntercept case infinity loop.

Solution

This is my solution.

  • call update api on onPress event then save data without validation
  • run validation in useBuyerJourneyIntercept callback with error state management
const applyAttributeChange = useApplyAttributeChange();
const [error, setError] = useState("");

useBuyerJourneyIntercept(({canBlockProgress}) => {

  if (canBlockProgress && isInValid(data)) {
    return {
      behavior : 'block';
      reason: 'invalid',
      perform: () => {
        setError('data is invalid')
      }
    }
  }

  return {
    behavior : 'allow';
    perform: () => {
      setError('')
    }
  };
});

const onPress = () => {
  applyAttributeChange(data);
};

return (
  <Text>{error}</Text>
  <Button onPress={onPress}></Button>
)
1 Like