Open In App

Create a Currency Converter using React-Native

Last Updated : 01 Jun, 2025
Summarize
Comments
Improve
Suggest changes
Share
Like Article
Like
Report

In this article, we will build a currency converter using react native. This app serves as a valuable tool for travelers, business professionals, and anyone who frequently deals with international currencies. It enables users to effortle­ssly convert one currency to another.

Create-a-Currency-Converter_

To give you a better idea of what we’re going to create, let’s watch a demo video.

Demo Video

Playground

Note: This Section is to interact with the app which you are going to build.


Prerequisites

Step-by-Step Implementation

Step 1: Create a React Native Project

Now, create a project with the following command.

npx create-expo-app app-name --template

Note: Replace the app-name with your app name for example : react-native-demo-app

Next, you might be asked to choose a template. Select one based on your preference as shown in the image below. I am selecting the blank template because it will generate a minimal app that is as clean as an empty canvas in JavaScript.

It completes the project creation and displays a message: "Your Project is ready!" as shown in the image below.

Now go into your project folder, i.e., react-native-demo

cd app-name

Project Structure:

Step 2: Run  Application

Start the server by using the following command.

npx expo start

Then, the application will display a QR code.

  • For the Android users,
    • For the Android Emulator, press " a" as mentioned in the image below.
    • For the Physical Device, download the " Expo Go " app from the Play Store. Open the app, and you will see a button labeled " Scan QR Code. " Click that button and scan the QR code; it will automatically build the Android app on your device.
  • For IOS users, simply scan the QR code using the Camera app.
  • If you're using a web browser, it will provide a local host link that you can use as mentioned in the image below.

Step 3: Update dependencies

Updated dependencies in the package.json file will look like:

"dependencies": {
"react-native-paper": "^5.14.0",
"react-native-modal-dropdown": "^1.0.2",
}

Now, run the following command to install the new dependencies.

npm install

Step 4: Start Coding

- Approach:

In this approach, we'll create a user-friendly currency conversion UI with input fields, dropdowns for currency selection, a conversion button, and real-time exchange rate data from exchange­rate-exchangerate-api.com. A currency-swapping feature will be added, and conversion details will be displayed upon completion.

Let's dive into the code in detail.

Import libraries:

Import required libraries at the top of the file.

JavaScript
// Importing necessary React hooks
import {
	useState,
	useEffect,
	useCallback
} from "react";
// Importing required components from React Native
import {
	View,
	Text,
	TextInput,
	TouchableOpacity
} from "react-native";
// Importing the dropdown component for currency selection
import ModalDropdown from "react-native-modal-dropdown";
// Importing external styles from styles.js file
import { styles } from "./styles.js";

StyleSheet:

Create a StyleSheet to style components like container, subcontainer, header, etc.

JavaScript
import { StyleSheet } from "react-native";

// Define a StyleSheet object to style the app components
const styles = StyleSheet.create({
  // Main container of the screen
  container: {
    flex: 1, // Occupies full height
    justifyContent: "center", // Centers content vertically
    alignItems: "center", // Centers content horizontally
    backgroundColor: "#f5f5f5" // Light grey background color
  },

  // Inner container that holds the converter UI
  subcontainer: {
    shadowColor: "rgba(0, 0, 0, 0.2)", // Shadow color for iOS
    shadowOffset: {
      width: 0, // No horizontal shadow
      height: 6 // Vertical shadow
    },
    shadowOpacity: 1, // Full shadow opacity
    shadowRadius: 15, // Shadow blur radius
    elevation: 5, // Shadow elevation for Android
    padding: 40, // Padding inside the container
    borderRadius: 20, // Rounded corners
    backgroundColor: "#ffffff" // White background
  },

  // Header title style
  header: {
    fontSize: 28, // Large font size
    fontWeight: "bold", // Bold text
    marginBottom: 20, // Space below the header
    color: "green" // Text color
  },

  // Common wrapper for inputs and dropdowns
  inputContainer: {
    flexDirection: "row", // Layout children in a row
    alignItems: "center", // Align children vertically centered
    marginVertical: 10 // Vertical spacing
  },

  // Label text style
  label: {
    fontSize: 19, // Medium font size
    marginRight: 10, // Space to the right of label
    color: "#333", // Dark gray text color
    fontFamily: "Pacifico" // Custom font for styling
  },

  // TextInput field style
  input: {
    flex: 1, // Occupies full horizontal space in its container
    borderWidth: 1, // Border thickness
    borderColor: "#ccc", // Light grey border color
    borderRadius: 10, // Rounded input corners
    paddingHorizontal: 10, // Left and right padding inside the input
    height: 40, // Fixed height
    color: "#333" // Text color
  },

  // Dropdown selector style
  dropdown: {
    width: 150, // Fixed width
    height: 40, // Fixed height
    borderWidth: 1, // Border width
    borderColor: "#ccc", // Border color
    borderRadius: 4, // Rounded corners
    paddingHorizontal: 10, // Padding inside the dropdown
    justifyContent: "center", // Center content vertically
    color: "#333" // Dropdown text color
  },

  // Convert button style
  convertButton: {
    backgroundColor: "#007BFF", // Blue background
    borderRadius: 4, // Rounded corners
    paddingVertical: 12, // Top and bottom padding
    paddingHorizontal: 24, // Left and right padding
    marginTop: 20, // Space above the button
    shadowColor: "rgba(0, 123, 255, 0.5)", // Shadow color
    shadowOffset: {
      width: 0, // No horizontal offset
      height: 3 // Vertical shadow
    },
    shadowOpacity: 1, // Shadow visibility
    shadowRadius: 15, // Shadow blur radius
    elevation: 3 // Android elevation for shadow
  },

  // Text inside convert button
  convertButtonText: {
    color: "white", // White text
    fontSize: 18, // Medium font size
    fontWeight: "bold", // Bold text
    textAlign: "center" // Center text horizontally
  },

  // Converted result text
  result: {
    marginTop: 20, // Space above the result
    fontSize: 18, // Medium font
    color: "#333" // Dark text color
  },

  // Style for the swap button (between currencies)
  swapButton: {
    backgroundColor: "#ddd", // Light grey background
    borderRadius: 50, // Fully rounded button
    width: 45, // Fixed width
    height: 40, // Fixed height
    justifyContent: "center", // Center content vertically
    alignItems: "center", // Center content horizontally
    marginBottom: 10 // Space below the button
  },

  // Swap icon text style
  swapButtonText: {
    fontSize: 30, // Large font size for swap icon
    textAlign: "center", // Centered horizontally
    color: "red", // Red color for emphasis
    marginBottom: 10 // Additional spacing below
  }
});

export { styles };

Title Text:

This title explains what the app does. We use the text "Currency Converter" to show that the app is to convert currency.

JavaScript
{/* Title-Text */}
<Text style={styles.header}>
	Currency Converter
</Text>

- Amount Section:

This section includes,

  • Text component having " Amount " as text to indicate that the below TextInput is take the amount from the user.
  • TextInput component is to take input from user, When the user entering any text or modifying the text inside the TextInput component it will send that input text to setAmount function using onChangeText prop in TextInput component, which will assign that text to amount state variable and that amount state variable further used in display text entered by user in TextInput component.
JavaScript
// State to store the input amount from user
const [amount, setAmount] = useState("");

{/* Label and input for amount */}
<Text style={styles.label}>Amount:</Text>
<View style={styles.inputContainer}>
	<TextInput
		style={styles.input}
		value={amount}
		onChangeText={(text) => setAmount(text)} // Update amount state
		keyboardType="numeric" // Only numeric input allowed
		placeholder="Enter amount"
		placeholderTextColor="#999"
	/>
</View>

- From Currency Section:

This section includes,

  • Text component having "From Currency" as text to indicate the below ModalDropdown is the type of currency user need to enter in TextInput.
  • ModalDropdown component is to display a list of categories of currency for example, USD, AED, AFN ..etc so, that user will select one of it.

when user tap on the dropdown button it will display all currencies using currencies state variable which is updated using useEffect and when user selects any one of it will update the state variable fromCurrency using setFormCurrency state function.

JavaScript
// State to store selected source currency (default: USD)
const [fromCurrency, setFromCurrency] = useState("USD");
// State to store list of available currencies
const [currencies, setCurrencies] = useState([]);

// useEffect hook to fetch all currencies on component mount
useEffect(() => {
	// Fetch exchange rates (base: USD)
	fetch('https://api.exchangerate-api.com/v4/latest/USD')
		.then((response) => response.json()) // Parse JSON
		.then((data) => {
			const currencyList = Object.keys(data.rates); // Extract list of currencies
			setCurrencies(currencyList); // Store in state
		})
		.catch((error) => {
			// Handle fetch error
			console.error("Error fetching currency data: ", error);
		});
}, []); // Empty dependency array ensures it runs once


{/* Dropdown for selecting 'from' currency */}
<Text style={styles.label}>From Currency:</Text>
<View style={styles.inputContainer}>
	<ModalDropdown
		style={styles.dropdown}
		options={currencies} // All available currencies
		defaultValue={fromCurrency} // Default selection
		onSelect={(_index, value) => setFromCurrency(value)} // Update state on selection
		renderRow={(option, index) => (
			<Text key={`from-${index}`} style={styles.dropdown}>
				{option}
			</Text>
		)}
	/>
</View>

- To Currency Section:

This is similar to the above section, but user need to select the currency which user want to convert to, from above selected currency.

JavaScript
// State to store selected target currency (default: EUR)
const [toCurrency, setToCurrency] = useState("EUR");
// State to store list of available currencies
const [currencies, setCurrencies] = useState([]);

{/* Dropdown for selecting 'to' currency */}
<Text style={styles.label}>To Currency:</Text>
<View style={styles.inputContainer}>
	<ModalDropdown
		style={styles.dropdown}
		options={currencies} // All available currencies
		defaultValue={toCurrency}
		onSelect={(_index, value) => setToCurrency(value)} // Update state
		renderRow={(option, index) => (
			<Text key={`to-${index}`} style={styles.dropdown}>
				{option}
			</Text>
		)}
	/>
</View>

- Convert Button:

This button is used to convert the currency from (Form Currency to To Currency) by calling convertCurrency function.

JavaScript
const convertCurrency = useCallback(() => {
	// If amount is empty, reset conversion result and exit
	if (!amount) {
		setConvertedAmount(null);
		return;
	}

	// Fetch exchange rates for selected "fromCurrency"
	fetch(`https://api.exchangerate-api.com/v4/latest/${fromCurrency}`)
		.then((response) => response.json()) // Parse JSON response
		.then((data) => {
			const exchangeRates = data.rates; // Extract rates
			const conversionRate = exchangeRates[toCurrency]; // Get rate for "toCurrency"

			if (conversionRate) {
				// Calculate and store converted value
				const result = parseFloat(amount) * conversionRate;
				setConvertedAmount(result.toFixed(2)); // Round to 2 decimal places
			} else {
				// If currency not found, show error
				setConvertedAmount("Invalid Currency");
			}
		})
		.catch((error) => {
			// Handle network or API errors
			console.error("Error converting currency: ", error);
		});
	// Dependencies: amount, fromCurrency, and toCurrency
}, [amount, fromCurrency, toCurrency]);

{/* Convert Button */}
<TouchableOpacity
	style={styles.convertButton}
	onPress={convertCurrency} // Call conversion function
>
	<Text style={styles.convertButtonText}>
		Convert
	</Text>
</TouchableOpacity>

- Swap Button:

This button will swap the From Currency and To Currency by calling the swapCurrencies function and setFormCurrency and setToCurrency state functions.

JavaScript
// State to store selected source currency (default: USD)
const [fromCurrency, setFromCurrency] = useState("USD");
// State to store selected target currency (default: EUR)
const [toCurrency, setToCurrency] = useState("EUR");
// Function to swap "from" and "to" currencies
const swapCurrencies = () => {
	setFromCurrency(toCurrency); // Swap logic
	setToCurrency(fromCurrency);
};

{/* Button to swap currencies */}
<TouchableOpacity
	style={styles.swapButton}
	onPress={swapCurrencies}
>
	<Text style={styles.swapButtonText}>
		&#8646; {/* Unicode for bidirectional arrow */}
	</Text>
</TouchableOpacity>

- Result Text:

Display the result after converting using the code below.

JavaScript
// State to store the input amount from user
const [amount, setAmount] = useState("");
// State to store selected source currency (default: USD)
const [fromCurrency, setFromCurrency] = useState("USD");
// State to store selected target currency (default: EUR)
const [toCurrency, setToCurrency] = useState("EUR");
// State to store list of available currencies
const [convertedAmount, setConvertedAmount] = useState(null);

{/* Display conversion result if available */}
{convertedAmount !== null && (
	<Text style={styles.result}>
		{amount} {fromCurrency} is - {convertedAmount} {toCurrency}
	</Text>
)}

Now, wrap all design code with a View component, return it from the App component, and place all methods and useStates within the App component. Ensure to export the App.

Complete Source Code

  • App.js: This file implements all the functionalities and renders the component.
  • styles.js: This file contains the styling for the components.
App.js
// Importing necessary React hooks
import {
	useState,
	useEffect,
	useCallback
} from "react";
// Importing required components from React Native
import {
	View,
	Text,
	TextInput,
	TouchableOpacity
} from "react-native";
// Importing the dropdown component for currency selection
import ModalDropdown from "react-native-modal-dropdown";
// Importing external styles from styles.js file
import { styles } from "./styles.js";

// Functional component definition
const App = () => {
	// State to store the input amount from user
	const [amount, setAmount] = useState("");
	// State to store selected source currency (default: USD)
	const [fromCurrency, setFromCurrency] = useState("USD");
	// State to store selected target currency (default: EUR)
	const [toCurrency, setToCurrency] = useState("EUR");
	// State to store list of available currencies
	const [currencies, setCurrencies] = useState([]);
	// State to store the converted amount after conversion
	const [convertedAmount, setConvertedAmount] = useState(null);
	// Function to convert currency based on selected values
	const convertCurrency = useCallback(() => {
		// If amount is empty, reset conversion result and exit
		if (!amount) {
			setConvertedAmount(null);
			return;
		}

		// Fetch exchange rates for selected "fromCurrency"
		fetch(`https://api.exchangerate-api.com/v4/latest/${fromCurrency}`)
			.then((response) => response.json()) // Parse JSON response
			.then((data) => {
				const exchangeRates = data.rates; // Extract rates
				const conversionRate = exchangeRates[toCurrency]; // Get rate for "toCurrency"

				if (conversionRate) {
					// Calculate and store converted value
					const result = parseFloat(amount) * conversionRate;
					setConvertedAmount(result.toFixed(2)); // Round to 2 decimal places
				} else {
					// If currency not found, show error
					setConvertedAmount("Invalid Currency");
				}
			})
			.catch((error) => {
				// Handle network or API errors
				console.error("Error converting currency: ", error);
			});
		// Dependencies: amount, fromCurrency, and toCurrency
	}, [amount, fromCurrency, toCurrency]);

	// useEffect hook to fetch all currencies on component mount
	useEffect(() => {
		console.log("now");
		// Fetch exchange rates (base: USD)
		fetch('https://api.exchangerate-api.com/v4/latest/USD')
			.then((response) => response.json()) // Parse JSON
			.then((data) => {
				const currencyList = Object.keys(data.rates); // Extract list of currencies
				setCurrencies(currencyList); // Store in state
			})
			.catch((error) => {
				// Handle fetch error
				console.error("Error fetching currency data: ", error);
			});
	}, []); // Empty dependency array ensures it runs once

	// Function to swap "from" and "to" currencies
	const swapCurrencies = () => {
		setFromCurrency(toCurrency); // Swap logic
		setToCurrency(fromCurrency);
	};

	// Render UI
	return (
		<View style={styles.container}>
			<View style={styles.subcontainer}>
				{/* Title-Text */}
				<Text style={styles.header}>
					Currency Converter
				</Text>

				{/* Label and input for amount */}
				<Text style={styles.label}>Amount:</Text>
				<View style={styles.inputContainer}>
					<TextInput
						style={styles.input}
						value={amount}
						onChangeText={(text) => setAmount(text)} // Update amount state
						keyboardType="numeric" // Only numeric input allowed
						placeholder="Enter amount"
						placeholderTextColor="#999"
					/>
				</View>

				{/* Dropdown for selecting 'from' currency */}
				<Text style={styles.label}>From Currency:</Text>
				<View style={styles.inputContainer}>
					<ModalDropdown
						style={styles.dropdown}
						options={currencies} // All available currencies
						defaultValue={fromCurrency} // Default selection
						onSelect={(_index, value) => setFromCurrency(value)} // Update state on selection
						renderRow={(option, index) => (
							<Text key={`from-${index}`} style={styles.dropdown}>
								{option}
							</Text>
						)}
					/>
				</View>

				{/* Button to swap currencies */}
				<TouchableOpacity
					style={styles.swapButton}
					onPress={swapCurrencies}
				>
					<Text style={styles.swapButtonText}>
						&#8646; {/* Unicode for bidirectional arrow */}
					</Text>
				</TouchableOpacity>

				{/* Dropdown for selecting 'to' currency */}
				<Text style={styles.label}>To Currency:</Text>
				<View style={styles.inputContainer}>
					<ModalDropdown
						style={styles.dropdown}
						options={currencies} // All available currencies
						defaultValue={toCurrency}
						onSelect={(_index, value) => setToCurrency(value)} // Update state
						renderRow={(option, index) => (
							<Text key={`to-${index}`} style={styles.dropdown}>
								{option}
							</Text>
						)}
					/>
				</View>

				{/* Convert Button */}
				<TouchableOpacity
					style={styles.convertButton}
					onPress={convertCurrency} // Call conversion function
				>
					<Text style={styles.convertButtonText}>
						Convert
					</Text>
				</TouchableOpacity>

				{/* Display conversion result if available */}
				{convertedAmount !== null && (
					<Text style={styles.result}>
						{amount} {fromCurrency} is - {convertedAmount} {toCurrency}
					</Text>
				)}
			</View>
		</View>
	);
};

export default App;
styles.js
//styles.js

import { StyleSheet } from "react-native";

const styles = StyleSheet.create({
container: {
	flex: 1,
	justifyContent: "center",
	alignItems: "center",
	backgroundColor: "#f5f5f5"
},
subcontainer: {
	shadowColor: "rgba(0, 0, 0, 0.2)",
	shadowOffset: {
	width: 0,
	height: 6
	},
	shadowOpacity: 1,
	shadowRadius: 15,
	elevation: 5,
	padding: 40,
	borderRadius: 20,
	backgroundColor: "#ffffff"
},
header: {
	fontSize: 28,
	fontWeight: "bold",
	marginBottom: 20,
	color: "green"
},
inputContainer: {
	flexDirection: "row",
	alignItems: "center",
	marginVertical: 10
},
label: {
	fontSize: 19,
	marginRight: 10,
	color: "#333",
	fontFamily: "Pacifico"
},
input: {
	flex: 1,
	borderWidth: 1,
	borderColor: "#ccc",
	borderRadius: 10,
	paddingHorizontal: 10,
	height: 40,
	color: "#333"
},
dropdown: {
	width: 150,
	height: 40,
	borderWidth: 1,
	borderColor: "#ccc",
	borderRadius: 4,
	paddingHorizontal: 10,
	justifyContent: "center",
	color: "#333"
},
convertButton: {
	backgroundColor: "#007BFF",
	borderRadius: 4,
	paddingVertical: 12,
	paddingHorizontal: 24,
	marginTop: 20,
	shadowColor: "rgba(0, 123, 255, 0.5)",
	shadowOffset: {
	width: 0,
	height: 3
	},
	shadowOpacity: 1,
	shadowRadius: 15,
	elevation: 3
},
convertButtonText: {
	color: "white",
	fontSize: 18,
	fontWeight: "bold",
	textAlign: "center"
},
result: {
	marginTop: 20,
	fontSize: 18,
	color: "#333"
},
swapButton: {
	backgroundColor: "#ddd",
	borderRadius: 50,
	width: 45,
	height: 40,
	justifyContent: "center",
	alignItems: "center",
	marginBottom: 10
},
swapButtonText: {
	fontSize: 30,
	textAlign: "center",
	color: "red",
	marginBottom: 10
}
});

export { styles };

Output


Similar Reads