Custom Hooks in React and Currency Convertor
In this blog, we'll explore key concepts for building your own React project, Currency Converter. Along the way, we'll learn how to create custom hooks to enhance your project. Let’s get started.
Code is available on GitHub: https://github.com/omkar-2483/currency_convertor
What is Hook actually?
Take this example:
const [count, setCount] = useState(0);
If you think about the useState
hook, it works like a function that takes an initial value (in this case, 0
) and returns an array with two items—count
and setCount
.
In essence, a hook is simply a function that serves a specific purpose in React, such as managing state or side effects. The great thing is, just like React's built-in hooks, we can create our own custom hooks to encapsulate reusable logic.
Creating Custom Hook
Let’s start by organizing our hooks. Create a new folder called hooks
, and inside it, create a new JavaScript file for your custom hook.
For our first custom hook, we’ll call it useCurrencyInfo
.
import {useEffect, useState} from "react"
function useCurrencyInfo(currency){
const [data, setData] = useState({})
useEffect(() => {
fetch(`https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/${currency}.json`)
.then((res) => res.json())
.then((res) => setData(res[currency]))
console.log(data);
}, [currency])
console.log(data);
return data
}
export default useCurrencyInfo;
useCurrencyInfo Hook:
It fetches currency information from an API based on the provided
currency
parameter.The hook uses
useState
to store fetched data anduseEffect
to fetch it when thecurrency
changes.The hook returns the currency data, which can be used in any component.
Now you can import and use useCurrencyInfo
in your component!
Create Components for reusability
let's create an InputBox
component that can be used to take user inputs for currency conversion.
import React, { useId } from "react";
function InputBox({
label,
amount,
onAmountChange,
onCurrencyChange,
currencyOptions = [],
selectCurrency = "usd",
amountDisable = false,
currencyDisable = false,
className = "",
}) {
const amountInputId = useId();
return (
<div className={`bg-white p-3 rounded-lg text-sm flex ${className}`}>
<div className="w-1/2">
<label
htmlFor={amountInputId}
className="text-black/40 mb-2 inline-block"
>
{label}
</label>
<input
id={amountInputId}
className="outline-none w-full bg-transparent py-1.5"
type="number"
placeholder="Amount"
disabled={amountDisable}
value={amount}
onChange={(e) =>
onAmountChange && onAmountChange(Number(e.target.value))
}
/>
</div>
<div className="w-1/2 flex flex-wrap justify-end text-right">
<p className="text-black/40 mb-2 w-full">Currency Type</p>
<select
className="rounded-lg px-1 py-1 bg-gray-100 cursor-pointer outline-none"
value={selectCurrency}
onChange={(e) => onCurrencyChange && onCurrencyChange(e.target.value)}
disabled={currencyDisable}
>
{currencyOptions.map((currency) => (
<option key={currency} value={currency}>
{currency}
</option>
))}
</select>
</div>
</div>
);
}
export default InputBox;
- The
useId
hook is a new React hook that generates a unique ID for elements. It's particularly useful for accessible form elements where thelabel
andinput
need to be associated.
Props:
label
: Displays a custom label for the input field.amount
andonAmountChange
: These manage the input value for the amount and its corresponding change handler.currencyOptions
andonCurrencyChange
: These allow the user to select different currencies and handle dropdown changes dynamically.amountDisable
andcurrencyDisable
: Control whether the amount input and currency dropdown are enabled or disabled. This is useful when you need to lock a field based on user flow.
Use useCurrencyInfo hook and InputBox component in App.js:
import { useState } from "react";
import { InputBox } from "./components";
import useCurrencyInfo from "./hooks/useCurrencyInfo";
function App() {
const [amount, setAmount] = useState(0);
const [from, setFrom] = useState("usd");
const [to, setTo] = useState("inr");
const [convertedAmount, setConvertedAmount] = useState(0);
const currencyInfo = useCurrencyInfo(from);
const options = Object.keys(currencyInfo);
const swap = () => {
setFrom(to);
setTo(from);
setConvertedAmount(amount);
setAmount(convertedAmount);
};
const convert = () => {
setConvertedAmount(amount * currencyInfo[to]);
};
return (
<div
className="w-full h-screen flex flex-wrap justify-center items-center bg-cover bg-no-repeat"
style={{
backgroundImage: `url('https://images.unsplash.com/photo-1621378864046-0122e4a415a5?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D')`,
}}
>
<div className="w-full">
<div className="w-full max-w-md mx-auto border border-gray-60 rounded-lg p-5 backdrop-blur-sm bg-white/30">
<form
onSubmit={(e) => {
e.preventDefault();
convert();
}}
>
<div className="w-full mb-1">
<InputBox
label="From"
amount={amount}
currencyOptions={options}
onCurrencyChange={(currency) => setAmount(amount)}
selectCurrency={from}
onAmountChange={(amount) => setAmount(amount)}
/>
</div>
<div className="relative w-full h-0.5">
<button
type="button"
className="absolute left-1/2 -translate-x-1/2 -translate-y-1/2 border-2 border-white rounded-md bg-blue-600 text-white px-2 py-0.5"
onClick={swap}
>
swap
</button>
</div>
<div className="w-full mt-1 mb-4">
<InputBox
label="To"
amount={convertedAmount}
currencyOptions={options}
onCurrencyChange={(currency) => setTo(currency)}
selectCurrency={from}
amountDisable
/>
</div>
<button
type="submit"
className="w-full bg-blue-600 text-white px-4 py-3 rounded-lg"
>
Convert {from.toUpperCase()} to {to.toUpperCase()}
</button>
</form>
</div>
</div>
</div>
);
}
export default App;
Creating a Currency Converter project in React helps you understand how to build custom hooks and reusable components. Custom hooks allow you to organize and reuse logic easily, while components like InputBox make your code more modular. These techniques make it easier to manage and scale your React projects effectively.
Subscribe to my newsletter
Read articles from Omkar Kasture directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Omkar Kasture
Omkar Kasture
MERN Stack Developer, Machine learning & Deep Learning