Demo project showcasing mastery of React, best practices, advanced patterns, and a modern web stack.
This codebase is intentionally crafted as a teaching/demo project. It highlights production-grade techniques while staying approachable:
- Modern React 19 with TypeScript and Vite 7
- Robust data and realtime layers (TanStack Query + resilient WebSocket client)
- Clean architecture (services, providers, hooks, stores, entities, components)
- Strong error handling strategy (error boundaries + global error manager + typed API errors)
- Performance-conscious rendering (rAF batching, memoization, selective subscriptions)
- Opinionated quality gates (strict TS, type-aware ESLint, tests with Vitest/MSW)
- Live market data via WebSocket with:
- Exponential backoff + jitter reconnection
- Heartbeat pings and smart close-code handling
- Message queueing while disconnected
- Online/offline awareness
- Markets page and trade page with:
- Candlestick chart, order book, live trades, and tickers
- Favorites with cross‑tab sync via localStorage events
- Sorting, filtering, and search ergonomics
- HTTP layer built on Axios with a typed
APIClient<T>and unifiedAPIError - React Query for cache, retries, and error boundary interop
- Typed global state with Zustand stores
- Defensive error boundaries with isolation per section
- Runtime/UI: React 19, React Router 7, Bootstrap 5
- Data: TanStack React Query 5, Axios
- State: Zustand 5
- Forms/Validation: React Hook Form, Zod
- Realtime: Custom WebSocket client (browser native WS)
- Tooling: Vite 7, TypeScript 5 (strict), ESLint (type-aware), Vitest + Testing Library + MSW
Key directories and responsibilities:
src/services/api-client.ts: Generic, typed HTTP client that normalizes errors intoAPIErrorws-client.ts: Resilient WebSocket client (reconnect + queue + heartbeat)
src/providers/webSocketProvider.tsx: App-scoped WS instance wired via React Context
src/hooks/useMarkets.ts: Markets query with sensible cache timesuseWireSocket.ts: Batches WS messages withrequestAnimationFrameinto stores
src/store/(Zustand)tickerStore.ts,bookStore.ts,tradeStore.ts,candleStore.ts
src/utils/globalErrorHandler.ts: Catches unhandled rejections/JS errors and filters benign noise
src/config/constants.ts: Centralized app, query, WS, and cache configuration
src/pages/andsrc/components/- Error boundaries, candlesticks, order book, trades, tickers, etc.
Vite dev server proxies HTTP and WS requests to Poloniex (see vite.config.ts) to simplify local development and CORS.
- TypeScript strict mode with additional compiler safety checks
- Type-aware ESLint config; consistent
import typeusage - Error boundaries with per-section isolation and reset keys
- Global error manager for cases boundaries can’t catch (e.g., unhandled rejections)
- Unified error shape (
APIError) to interop with React Query’sthrowOnError - Realtime resiliency: reconnect/backoff/jitter, queueing, heartbeat, online/offline listeners
- Render throughput:
requestAnimationFramebatching for fast WS bursts - State updates via small focused stores and selectors (Zustand)
- Cross-tab persistence using the
storageevent (favorites) - Proxying WS/HTTP in dev for clean origins and headers
Prerequisites:
- Node.js 18+ (LTS recommended)
- npm 9+ (or your favorite package manager)
Install dependencies:
npm installRun the app (Vite dev server):
npm run devThen open http://localhost:5173
Build for production:
npm run buildPreview the production build locally:
npm run previewQuality and tests:
# Lint (type-aware ESLint)
npm run lint
# Unit/integration tests (Vitest)
npm run test
# Coverage report
npm run test:coverage
# Test UI runner
npm run test:ui- Exponential backoff with jitter and a max delay cap
- Differentiates retryable vs non‑retryable close codes
- Queues outbound messages when disconnected, flushes on open
- Heartbeat ping to keep idle connections alive
- Online/offline awareness with auto reconnect when network restores
- Buffers ticker/candle/book/trade messages and flushes via
requestAnimationFrame - Minimizes render storms during high‑throughput bursts
- Normalizes payloads into numeric types before store writes
ErrorBoundaryWrapperwith section isolation and React Query reset integrationAPIErrorfor HTTP: status, data payload, and retryability hintsGlobalErrorManagerto capture unhandled rejections and JS errors, filtering benign browser noise
- Dev proxy targets for HTTP (
/poloniex) and WS (/pws) are configured invite.config.ts. - No API keys are required for this demo; endpoints are public. If your environment requires different hosts, adjust the proxy targets or wire environment variables (e.g.,
VITE_API_BASE_URL,VITE_WS_URL).
- More test coverage around WS reconnection and store logic
- Storybook for component documentation
- Accessibility audit (ARIA, keyboard navigation, focus management)
- Discriminated unions for WS message shapes end‑to‑end
- Immer‑powered immutable updates for large store merges
MIT — use freely for learning and demos.