Custom Hooks in React and Currency Convertor

Omkar KastureOmkar Kasture
4 min read

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 and useEffect to fetch it when the currency 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 the label and input need to be associated.

Props:

  • label: Displays a custom label for the input field.

  • amount and onAmountChange: These manage the input value for the amount and its corresponding change handler.

  • currencyOptions and onCurrencyChange: These allow the user to select different currencies and handle dropdown changes dynamically.

  • amountDisable and currencyDisable: 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.

0
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