Howdy!

This time we will be walking through custom components and calling native code to achieve currency formatted text that was used in the TicTok task monitor project. I initially used masked text for formatted text, but since there became more currencies I decided to create a component and do the currency formatting in Android/iOS code. So, here are the steps you need to do and code samples for currency formatted text component using a native module. 😎

Let's start with Android code. First, we need to create the Java module:

import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

import java.text.NumberFormat;
import java.util.Currency;
import java.util.Locale;

public class CurrencyFormatterModule extends ReactContextBaseJavaModule {

    public CurrencyFormatterModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    public String getName() {
        return "CurrencyFormatter";
    }

    @ReactMethod
    public void format(double amount, String currencyCode, Callback callback) {
        try {
            Currency currency = Currency.getInstance(currencyCode);
            NumberFormat format = NumberFormat.getCurrencyInstance(Locale.getDefault());
            format.setMaximumFractionDigits(currency.getDefaultFractionDigits());
            format.setCurrency(currency);

            callback.invoke(format.format(amount));
        } catch (Exception e) {
            callback.invoke("-");
        }
    }
}

What we have here is the minimum sample of a native module for Android. There are 2 key points to acknowledge. First is the getName() method, this will be the name we expose for JavaScript which we will be covering later. The second one is the format method. All bridge methods return void, so we are forced to use Callback to deliver the formatted text back to Javascript.

Next part is to get our module exposed. For that we need to create our own ReactPackage and construct the module:

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.example.modules.CurrencyFormatterModule;

public class MyPackage implements ReactPackage {

    @Override
    public List createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    @Override
    public List createNativeModules(
        ReactApplicationContext reactContext) {
        List modules = new ArrayList<>();

        modules.add(new CurrencyFormatterModule(reactContext));

        return modules;
    }
}

This package is like any other, it creates the modules and view managers for your own native classes. And to include this in the app you simply add it in your Application class:

protected List getPackages() {
    return Arrays.asList(
        new MainReactPackage(),
        new MyPackage());
        }

That's all you need to do in Android code. Let's go through the equivalent for iOS. Exposing the module is a little bit more direct, so we will be making 2 files.

CurrencyFormatter.h

#import <React/RCTBridgeModule.h>

@interface CurrencyFormatter : NSObject 
@end

CurrencyFormatter.m

#import "CurrencyFormatter.h"

@implementation CurrencyFormatter

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(format:(NSNumber * __nonnull)amount currencyCode:(NSString * __nonnull)currencyCode callback:(RCTResponseSenderBlock)callback)
{
    NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
    [formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
    [formatter setCurrencyCode:(NSString *) currencyCode];

    callback(@[[formatter stringFromNumber:amount]]);
}

@end

And that's it. Easy right? But wait, we are still missing the Javascript part. Let's create CurrencyFormatter.js file which will be the key file in our JS code to export the native module:

import { NativeModules } from 'react-native';

module.exports = NativeModules.CurrencyFormatter;

Here you can see NativeModules.CurrencyFormatter which is the match for Android module name and iOS interface class name. And to get this all into action, let's create custom React component for it.

import React from 'react';
import { Text, ViewPropTypes } from 'react-native';
import PropTypes from 'prop-types';
import CurrencyFormatter from '../modules/CurrencyFormatter';

export default class AmountText extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      text: '',
    };

    this.formatText(props);
  }

  componentWillReceiveProps(newProps) {
    this.formatText(newProps);
  }

  formatText(props) {
    if (props.amount !== undefined && props.currencyCode !== undefined) {
      CurrencyFormatter.format(
        props.amount, props.currencyCode,
        (formattedText) => {
          this.setState({ text: formattedText });
        },
      );
    }
  }

  render() {
    return (
      
        {this.state.text}
      
    );
  }
}

AmountText.defaultProps = {
  amount: undefined,
  currencyCode: undefined,
  style: {},
};

AmountText.propTypes = {
  amount: PropTypes.number,
  currencyCode: PropTypes.string,
  style: ViewPropTypes.style,
};

And before we go through what's happening there, here is sample usage:

<AmountText
  style={styles.myAmountStyle}
  amount={100.50}
  currencyCode={'USD'}
/>

We have defined 3 properties which are amount and currencyCode for the amount itself and style for getting that fancy font and color in. Our component will render state 'text' which is the formatted text. We are using state here because the formatting function is asynchronous, so for a very brief moment of time, initially, the component will render nothing. If you have hooked the properties with e.g Redux, the AmountText will automatically update the rendered value when any of those properties change.

There we go, we have created our very first custom module and component. Cheers and happy coding 🙂

 


 

About the Author:

Niko is Finlabs mobile development guru. Working in a team, or as a one-man show, Nikos skills in mobile development are some of the best and fastest around. Niko has strong experience in modern development methods and technologies and has flexed his development muscles at the likes of Nokia and Osuuspankki, where he was a leading member of teams creating global, award-winning products.

On our projects, Niko is often the driving force. His passion to push himself to the edge encourages other team members to push themselves beyond their regular limits.