T

TechIdea

Ecosystem

Back to react Projects
Intermediate Level

Cryptocurrency Real-Time Dashboard

Build a professional, real-time cryptocurrency dashboard that tracks the top 100 coins using the CoinGecko API. You will implement live price charts, portfolio tracking, and dark mode.

The Problem

Many beginner React tutorials focus on static data. To become a mid-level engineer, you must know how to handle complex, rapidly changing asynchronous data streams, manage caching, and render heavy data visualizations without freezing the browser.

Real-World Use Case

This architecture is identical to how financial tech (FinTech) companies build internal trading terminals, analytics dashboards, and consumer-facing portfolio apps (like Coinbase or Binance).

Technology Stack

React 18

For the core UI library and functional component architecture.

React Query

To manage server state, caching, and auto-refetching of live coin prices.

Tailwind CSS

For rapid, utility-first styling and easy Dark Mode implementation.

Recharts

A composable charting library built on React components for rendering price graphs.

Architecture & Design

Folder Structure

src/
├── components/
│   ├── CoinTable.tsx
│   ├── PriceChart.tsx
│   └── PortfolioWidget.tsx
├── hooks/
│   ├── useCoins.ts
│   └── usePortfolio.ts
├── services/
│   └── api.ts
└── App.tsx

API Design

GETGET /api/v3/coins/markets

Fetches top 100 coins with current prices and market cap.

GETGET /api/v3/coins/{id}/market_chart

Fetches 7-day historical price data for the chart.

Step-by-Step Implementation

1

Setup React Query and API Service

Initialize the query client to manage all of our external API requests.

react
import { QueryClient, QueryClientProvider } from 'react-query';
import { App } from './App';

// We configure the client to not retry immediately on failure
// and to keep data fresh for 60 seconds to avoid API rate limits.
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 60000,
      retry: 1,
    },
  },
});

export default function Root() {
  return (
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>
  );
}

Code Explanation

React Query acts as a global cache for your server data. By setting `staleTime: 60000`, we ensure we don't spam the CoinGecko API every time a component re-renders.

2

Create the useCoins Custom Hook

Abstract the data fetching logic away from the UI components.

react
import { useQuery } from 'react-query';

const fetchCoins = async () => {
  const res = await fetch('https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100');
  if (!res.ok) throw new Error('Network response was not ok');
  return res.json();
};

export const useCoins = () => {
  return useQuery('coins', fetchCoins, {
    // Auto refresh data every 60 seconds
    refetchInterval: 60000, 
  });
};

Code Explanation

By wrapping `useQuery` in a custom hook, any component in our app can simply call `const { data } = useCoins();` without worrying about the actual fetch logic or caching.

3

Render the Data Table

Map over the cached data and render the coin list.

react
import { useCoins } from '../hooks/useCoins';

export function CoinTable() {
  const { data: coins, isLoading, error } = useCoins();

  if (isLoading) return <div>Loading market data...</div>;
  if (error) return <div>Error fetching data. Check your connection.</div>;

  return (
    <table className="min-w-full divide-y divide-gray-200">
      <thead>
        <tr>
          <th>Coin</th>
          <th>Price</th>
          <th>24h Change</th>
        </tr>
      </thead>
      <tbody>
        {coins.map((coin) => (
          <tr key={coin.id}>
            <td>{coin.name}</td>
            <td>${coin.current_price.toLocaleString()}</td>
            <td className={coin.price_change_percentage_24h > 0 ? 'text-green-500' : 'text-red-500'}>
              {coin.price_change_percentage_24h.toFixed(2)}%
            </td>
          </tr>
        ))}
      </tbody>
    </table>
  );
}

Code Explanation

This table automatically re-renders whenever React Query fetches new data in the background. The `toLocaleString()` method is used to format the currency nicely with commas.

Common Errors

CORS Policy Error

If you hit CORS issues during development with CoinGecko, ensure you are not passing complex custom headers in your fetch request, as public APIs often block them.

Too Many Requests (HTTP 429)

CoinGecko has a strict rate limit for free tiers. Increase the `staleTime` and `refetchInterval` in React Query to 60000ms (1 minute).

Security & Performance

Never store API keys in the frontend code. Fortunately, the free CoinGecko API doesn't require one, but if you upgrade to Pro, you must route requests through a Next.js or Node.js backend.

Sanitize any inputs if you add a 'Search Coin' feature to prevent XSS attacks.


Use React's `memo` or `useMemo` on the Recharts component. Charts are very heavy to render, and you don't want them re-rendering if the user just clicks a dark-mode toggle.

Implement windowing/virtualization (e.g., using `react-window`) if you decide to load all 10,000+ coins instead of just the top 100.

Interview Questions

Q: Why did you use React Query instead of `useEffect` for fetching?

A: useEffect requires manual management of loading states, error states, and caching. React Query handles deduplication, background refetching, and stale data automatically, resulting in less boilerplate and better UX.

Q: How would you handle real-time price updates (every second)?

A: Instead of polling the REST API every second (which would hit rate limits), I would open a WebSocket connection to a crypto provider like Binance, and update the global state whenever a message is received.

Growth Newsletter

Get practical AI tools, SEO tips, and growth guides weekly.

Join creators, students, and businesses scaling with TechIdea.