0

I have a question about updating UI in real-time (when typing). Is this the right approach?

I have this code:

Regex Method:

determineCardBrand(number) {
    var re = new RegExp("^4");
    var reMC = new RegExp(
      "/^(5[1-5][0-9]{14}|2(22[1-9][0-9]{12}|2[3-9][0-9]{13}|[3-6][0-9]{14}|7[0-1][0-9]{13}|720[0-9]{12}))$/",
    );

    if (number.match(re) != null) {
      return "Visa";
    } else if (number.match(reMC) != null) {
      return "MasterCard";
    } else {
      return "";
    }
  }

View code snippet:

 <View style={{ flexDirection: "row" }}>
                <CardLogo
                  style={styles.cardLogo}
                  cardType={
                    cardNumber === ""
                      ? "Inactive"
                      : this.determineCardBrand(cardNumber)
                  }
                />
                <TextInputMask
                  underlineColorAndroid={"transparent"}
                  type={"credit-card"}
                  maxLength={19}
                  style={[Styles.paymentCardInput, { flexGrow: 1 }]}
                  onChangeText={cardNumber => {
                    this.setState({ cardNumber });
                    this.determineCardBrand(cardNumber);
                  }}
                  value={cardNumber}
                  returnKeyType="done"
                />
              </View>

Where I want to determine if what card number I type is associated to what CC brand (e.g. visa, mastercard, etc..). So as I type a card number, I want the card logo to change based on what I type for the number. CardLogo component has a switch statement that determines if type name is passed is e.g. Visa, then show the Visa logo.

Is this the right approach?

Normally, you can find out from the first four digits (I think) but sometimes just the first one e.g. like the visa card.. always starts with four. I tested out the above but for some reason, it only works for Visa or unknown CC, not Mastercard. I'm not sure if it's because of the Regex or the way I have the code setup above.

Euridice01
  • 2,510
  • 11
  • 44
  • 76
  • As far as I know, Mastercards do always have 5 as their first digit. Probably it's an issue with your regex. In my opinion, your approach looks fine. – Tim Dec 10 '19 at 12:57
  • [This](https://stackoverflow.com/questions/40775674/credit-card-input-validation-using-regular-expression-in-javascript) can help you out with the regex – Sunil Chaudhary Dec 10 '19 at 13:05

2 Answers2

1

You can do one improvement by adding cardType property to state, by doing this you would only need to determine card type once and it will little more readable as below.

<View style={{ flexDirection: "row" }}>
const { cardType, cardNumber } = this.state;
<CardLogo
    style={styles.cardLogo}
    cardType={cardType}
/>
<TextInputMask
    underlineColorAndroid={"transparent"}
    type={"credit-card"}
    maxLength={19}
    style={[Styles.paymentCardInput, { flexGrow: 1 }]}
    onChangeText={cardNumber => {
        const cardType = this.determineCardBrand(cardNumber);
        this.setState({ cardNumber, cardType });
    }}
    value={cardNumber}
    returnKeyType="done"
/>

With regards to determining mastercard, appearantly there is problem in your master card reg ex, below should work, regex taken from regexinfo

determineCardBrand(number) {
const visa = /^4[0-9]{12}(?:[0-9]{3})?$/;
const master = /^(?:5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}$/;

if (visa.test(number)) {
    return "Visa";
} else if (master.test(number)) {
    return "MasterCard";
} else {
    return "";
}}
Rajnikant
  • 2,176
  • 24
  • 23
  • In your example, you are still determining the cardtype for each onChangeText event. – Tim Dec 10 '19 at 13:16
  • @Tim what's bad about the code above? Can you explain it? – Euridice01 Dec 10 '19 at 21:03
  • @Tim I am determining cardType on cardNumberChange but cardType was not part of the state, and determined cardType was used at two places, one after this.setState and one more time inside the CardLogo component, hence suggested to promote cardType to state, calculate once and then just use from the state, also do you think using calculating something on change of some text justifies use of useEffect? If you want to use hooks then useReducer justifies the use case. – Rajnikant Dec 10 '19 at 21:50
0

In a functional component, you could use hooks, on compute the card brand in a useEffect, triggered each time card number changes. I think this would be more efficient since setState is asynchronous (and so you should not assume your state is up to date when calling determineCardBrand() right after setState).

[...]
const [cardNumber, setCardNumber] = useState('');
[...]
useEffect(() => {
  determineCardBrand();
}, [cardNumber]);
[...]
<TextInputMask
    underlineColorAndroid={"transparent"}
    type={"credit-card"}
    maxLength={19}
    style={[Styles.paymentCardInput, { flexGrow: 1 }]}
    onChangeText={cardNumber => {
        // const cardType = this.determineCardBrand(cardNumber); not needed anymore
        this.setCardNumber(cardNumber);
    }}
    value={cardNumber}
    returnKeyType="done"
/>

Computing the card brand is typically a side effect (depends on a state value), so useEffect would be the perfect tool (IMHO :). But you could also store the card brand in state, and setup const [cardBrand, setCardBrand] = useState('').

Note that this is the functional approach, using hooks introduced in 16.8, so this may not be a viable solution for you. But state is still asynchronous in class based component.

Florian Motteau
  • 3,467
  • 1
  • 22
  • 42
  • Can I use the above hook in my class component? I have a class component already? – Euridice01 Dec 10 '19 at 20:59
  • Considering the fact that you have `this.determineCardBrand(...)` in your code, I assume you have a class-based component. You could easily convert it to a functional component and use hooks : https://overreacted.io/how-are-function-components-different-from-classes/, https://medium.com/@Zwenza/functional-vs-class-components-in-react-231e3fbd7108, https://reactjs.org/docs/hooks-faq.html. Hooks are a brand new React feature, pushing functional components, but either solution will work. – Florian Motteau Dec 10 '19 at 21:14