In today’s interconnected world, dealing with different currencies is a common occurrence. Whether you’re traveling, shopping online, or managing international finances, having a reliable currency converter at your fingertips can be incredibly useful. This tutorial will guide you through building a simple, yet functional, currency converter application using Next.js, a popular React framework for building web applications. We’ll cover everything from setting up your project to fetching real-time exchange rates and displaying them in a user-friendly interface. This project is perfect for beginners and intermediate developers looking to expand their skills in Next.js, API integration, and front-end development.
Why Build a Currency Converter?
Currency converters are more than just a novelty; they serve a practical purpose. They help you:
- Understand Costs: Easily determine the equivalent cost of goods and services in your local currency when shopping online or traveling.
- Manage Finances: Simplify international money transfers and track your financial transactions across different currencies.
- Make Informed Decisions: Stay updated with the latest exchange rates to make informed investment and financial decisions.
Building this application provides a great opportunity to learn about:
- Next.js Fundamentals: Understanding the basics of Next.js, including components, pages, and routing.
- API Integration: Learning how to fetch data from external APIs and handle the responses.
- State Management: Managing the state of your application, such as the currency amounts and exchange rates.
- User Interface Design: Creating a user-friendly and intuitive interface for your application.
Project Setup
Let’s get started by setting up our Next.js project. Open your terminal and run the following command:
npx create-next-app currency-converter
cd currency-converter
This command creates a new Next.js project named “currency-converter” and navigates you into the project directory. Next, we need to install a few dependencies that we’ll use in our project:
npm install axios react-select
- axios: A popular library for making HTTP requests. We’ll use this to fetch exchange rates from an API.
- react-select: A customizable select component that provides a better user experience for selecting currencies.
Fetching Exchange Rates
The core of our currency converter is fetching the latest exchange rates. We’ll use a free API for this purpose. There are several free APIs available; for this tutorial, we’ll use the ExchangeRate-API. You can sign up for a free API key at ExchangeRate-API. Once you have your API key, you’ll need to store it securely, ideally in your environment variables. In a real-world application, never hardcode your API key directly into your code. Create a .env.local file in the root of your project and add your API key there:
# .env.local
NEXT_PUBLIC_API_KEY=YOUR_API_KEY
Replace `YOUR_API_KEY` with your actual API key. The `NEXT_PUBLIC_` prefix makes the variable accessible in the client-side code.
Now, let’s create a function to fetch the exchange rates. Create a new file named `utils/api.js` and add the following code:
import axios from 'axios';
const API_KEY = process.env.NEXT_PUBLIC_API_KEY;
const BASE_URL = 'https://v6.exchangerate-api.com/v6';
export const getExchangeRates = async (fromCurrency, toCurrency, amount) => {
try {
const response = await axios.get(
`${BASE_URL}/${API_KEY}/pair/${fromCurrency}/${toCurrency}/${amount}`
);
return response.data;
} catch (error) {
console.error('Error fetching exchange rates:', error);
throw error; // Re-throw the error for the component to handle
}
};
export const getCurrencies = async () => {
try {
const response = await axios.get(`${BASE_URL}/${API_KEY}/codes`);
return response.data;
} catch (error) {
console.error('Error fetching currencies:', error);
throw error;
}
};
This code defines two functions:
- `getExchangeRates`: This function takes the `fromCurrency`, `toCurrency`, and `amount` as arguments, constructs the API URL, and fetches the exchange rate. It uses the `axios` library to make the API request and returns the response data.
- `getCurrencies`: Fetches a list of available currencies from the API.
Building the UI with React Components
Now, let’s build the user interface for our currency converter. We’ll create a main component called `Converter.js` inside the `pages` directory (or create a components directory if you prefer to keep your components separate).
// pages/index.js
import React, { useState, useEffect } from 'react';
import Select from 'react-select';
import { getExchangeRates, getCurrencies } from '../utils/api';
const Converter = () => {
const [fromCurrency, setFromCurrency] = useState('USD');
const [toCurrency, setToCurrency] = useState('EUR');
const [amount, setAmount] = useState(1);
const [exchangeRate, setExchangeRate] = useState(null);
const [currencies, setCurrencies] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
const fetchCurrencies = async () => {
try {
const data = await getCurrencies();
// Convert the currency codes from array of objects to an array of objects for react-select
const formattedCurrencies = Object.entries(data.symbols).map(([code, name]) => ({
value: code,
label: `${code} - ${name}`,
}));
setCurrencies(formattedCurrencies);
} catch (error) {
setError('Failed to load currencies.');
}
};
fetchCurrencies();
}, []);
useEffect(() => {
const fetchExchangeRate = async () => {
if (!fromCurrency || !toCurrency) return;
setIsLoading(true);
setError(null);
try {
const data = await getExchangeRates(fromCurrency, toCurrency, amount);
setExchangeRate(data.conversion_result);
} catch (error) {
setError('Failed to fetch exchange rate.');
} finally {
setIsLoading(false);
}
};
fetchExchangeRate();
}, [fromCurrency, toCurrency, amount]);
const handleAmountChange = (e) => {
const value = parseFloat(e.target.value);
if (!isNaN(value)) {
setAmount(value);
}
};
return (
<div style="{{">
<h2>Currency Converter</h2>
{error && <p style="{{">{error}</p>}
<div>
<label>Amount:</label>
</div>
<div style="{{">
<div style="{{">
<label>From:</label>
c.value === fromCurrency)}
onChange={(selectedOption) => setFromCurrency(selectedOption.value)}
options={currencies}
placeholder="Select currency"
isSearchable
/>
</div>
<div style="{{">
<label>To:</label>
c.value === toCurrency)}
onChange={(selectedOption) => setToCurrency(selectedOption.value)}
options={currencies}
placeholder="Select currency"
isSearchable
/>
</div>
</div>
{isLoading ? (
<p>Loading...</p>
) : exchangeRate !== null && !error ? (
<p><b>{amount} {fromCurrency}</b> = <b>{exchangeRate.toFixed(2)} {toCurrency}</b></p>
) : null}
</div>
);
};
export default Converter;
Let’s break down this code:
- State Variables: We use `useState` hooks to manage the following state variables:
- `fromCurrency`: The currency to convert from (e.g., USD).
- `toCurrency`: The currency to convert to (e.g., EUR).
- `amount`: The amount to convert.
- `exchangeRate`: The calculated exchange rate.
- `currencies`: An array of available currencies fetched from the API.
- `isLoading`: A boolean to indicate whether the exchange rate is being fetched.
- `error`: A string to store any error messages.
- `useEffect` Hooks:
- The first `useEffect` hook fetches the list of available currencies from the API on component mount and updates the `currencies` state.
- The second `useEffect` hook fetches the exchange rate whenever `fromCurrency`, `toCurrency`, or `amount` changes. It calls the `getExchangeRates` function we defined earlier.
- `handleAmountChange` Function: This function updates the `amount` state when the user types in the input field, ensuring that the input is a valid number.
- JSX Structure: The component renders the following UI elements:
- An input field for the amount to convert.
- Two `react-select` components for selecting the source and target currencies.
- A loading indicator while fetching the exchange rate.
- The converted amount, displayed with the exchange rate, or an error message if something went wrong.
- Error Handling: The code includes error handling, displaying error messages to the user if the API request fails.
This code provides the basic functionality for the currency converter, allowing users to input an amount, select currencies, and see the converted result. Next, we’ll add some styling to make it look nicer.
Styling the Application
While the application is functional, it could use some styling to enhance its appearance and user experience. We’ll use inline styles in this example for simplicity, but in a larger project, you’d likely use a CSS-in-JS solution (like styled-components) or a CSS framework (like Tailwind CSS or Bootstrap) for better organization and maintainability. Update the `Converter.js` file with the following styles:
// pages/index.js
// ... (previous code)
return (
<div style="{{">
<h2>Currency Converter</h2>
{error && <p style="{{">{error}</p>}
<div>
<label>Amount:</label>
</div>
<div style="{{">
<div style="{{">
<label>From:</label>
c.value === fromCurrency)}
onChange={(selectedOption) => setFromCurrency(selectedOption.value)}
options={currencies}
placeholder="Select currency"
isSearchable
styles={{
control: (provided) => ({
...provided,
border: '1px solid #ccc',
borderRadius: '4px',
padding: '2px',
marginBottom: '10px',
}),
}}
/>
</div>
<div style="{{">
<label>To:</label>
c.value === toCurrency)}
onChange={(selectedOption) => setToCurrency(selectedOption.value)}
options={currencies}
placeholder="Select currency"
isSearchable
styles={{
control: (provided) => ({
...provided,
border: '1px solid #ccc',
borderRadius: '4px',
padding: '2px',
marginBottom: '10px',
}),
}}
/>
</div>
</div>
{isLoading ? (
<p>Loading...</p>
) : exchangeRate !== null && !error ? (
<p><b>{amount} {fromCurrency}</b> = <b>{exchangeRate.toFixed(2)} {toCurrency}</b></p>
) : null}
</div>
);
These styles improve the appearance of the input field, the select components, and the overall layout. Specifically, we’ve added:
- A container with a maximum width, margin, padding, border, and background color to provide a clean layout.
- Styles for the input field, including padding, border, and rounded corners.
- Styles for the `react-select` components to match the overall design.
With these styles, the application looks much more polished and user-friendly.
Running the Application
Now that we’ve built the currency converter, let’s run it. In your terminal, make sure you’re in the project directory and run the following command:
npm run dev
This command starts the Next.js development server. Open your web browser and go to `http://localhost:3000`. You should see your currency converter application running.
Common Mistakes and Troubleshooting
Here are some common mistakes and how to fix them:
- API Key Issues: If you get an error related to the API key, double-check that you’ve set up your `.env.local` file correctly, and that the environment variable name matches what you’re using in your code. Make sure the API key is valid.
- CORS Errors: If you encounter CORS (Cross-Origin Resource Sharing) errors, it means the API you’re using might not allow requests from your domain. This is less likely with the API we’re using, but if it happens, you might need to use a proxy server or configure CORS on the API server.
- Incorrect Currency Codes: Ensure that the currency codes you’re using are correct (e.g., USD for US Dollar, EUR for Euro). The API might return an error if you use invalid codes.
- Incorrect Dependencies: Double-check that you installed the dependencies correctly using `npm install`.
- Typos: Carefully review your code for any typos, especially in the API URLs, variable names, and component names.
Enhancements and Next Steps
This is a basic currency converter, but there are several ways to enhance it:
- Error Handling: Improve error handling by displaying more informative error messages to the user and logging errors for debugging.
- Currency Symbols: Display currency symbols alongside the currency codes for better readability. For example, instead of just “USD”, show “USD ($)”.
- Real-time Updates: Implement real-time updates of the exchange rates using WebSockets or Server-Sent Events (SSE).
- Currency History: Add a feature to display the historical exchange rates for a specific currency pair.
- User Preferences: Allow users to save their preferred currencies for quick access.
- More Advanced UI: Use a more sophisticated UI library (like Material UI, Chakra UI, or Ant Design) to create a more polished user interface.
- Testing: Write unit and integration tests to ensure the application functions correctly.
- Deployment: Deploy your application to a platform like Vercel or Netlify to make it accessible online.
Summary / Key Takeaways
In this tutorial, we’ve successfully built a simple currency converter application using Next.js. We’ve covered the essential steps, from setting up the project and fetching exchange rates from an API to creating a user-friendly interface. You’ve learned how to integrate external APIs, manage state with `useState` and `useEffect`, and use the `react-select` library for a better user experience. This project serves as a solid foundation for understanding Next.js and building more complex web applications. Remember to always handle errors gracefully, and consider the user experience when designing your application. With the knowledge gained from this tutorial, you can now explore more advanced features and build upon this foundation to create even more sophisticated applications.
FAQ
Q: How do I get an API key?
A: You can sign up for a free API key at ExchangeRate-API. Follow their instructions to create an account and obtain an API key.
Q: Where should I store my API key?
A: Store your API key in a `.env.local` file in the root of your project and use `process.env.NEXT_PUBLIC_API_KEY` to access it in your code. Never hardcode your API key directly into your code.
Q: How can I handle CORS errors?
A: If you encounter CORS errors, you might need to use a proxy server or configure CORS on the API server. In this specific case, the API used in this tutorial does not typically cause CORS issues, but it’s a good practice to be aware of the problem and its potential solutions.
Q: How can I improve the user interface?
A: You can improve the user interface by using a CSS framework (like Tailwind CSS or Bootstrap) or a UI component library (like Material UI, Chakra UI, or Ant Design). You can also customize the styles of the existing components.
Q: How do I deploy my application?
A: You can deploy your Next.js application to a platform like Vercel or Netlify. These platforms provide easy deployment and hosting options for web applications. You can also deploy to other platforms like AWS or Google Cloud.
Building this currency converter is a practical step towards mastering Next.js and front-end development. Experiment with the code, try different APIs, and add new features to expand your knowledge and create a more personalized application. Embrace the learning process, and don’t hesitate to explore new technologies and techniques to enhance your skills. The world of web development is constantly evolving, and the more you practice and experiment, the more proficient you will become.
