Skip to content

React Integration Guide

Learn how to integrate route optimization and mapping into your React applications using @route-optimization/react.

Installation

bash
npm install @route-optimization/react @route-optimization/core
# or
pnpm add @route-optimization/react @route-optimization/core
# or
yarn add @route-optimization/react @route-optimization/core

API Key Setup

Before using any components, configure your Google Maps API key:

bash
# .env
REACT_APP_GOOGLE_MAPS_API_KEY=your_api_key_here

Security

Never commit your API key to version control. Always use environment variables and add .env to your .gitignore file.

TIP

For production deployments, use your hosting platform's environment variable configuration (Vercel, Netlify, etc.). See Authentication Guide for best practices.

Core Concepts

The React package provides hooks that wrap the core functionality with React-specific state management:

  • useRouteMap - Main hook for map rendering and route management
  • useMapControls - Hook for map interaction controls
  • useRouteOptimization - Hook for route calculation and optimization
  • useOptimizationStatus - Hook for optimization progress tracking

Basic Map Rendering

Simple Route Map

tsx
import { useRouteMap } from '@route-optimization/react';

function RouteMapComponent() {
  const { mapRef, renderRoute, clearRoute, isReady } = useRouteMap({
    apiKey: 'YOUR_GOOGLE_MAPS_API_KEY',
    center: { lat: 13.7563, lng: 100.5018 }, // Bangkok
    zoom: 12,
  });

  const handleShowRoute = () => {
    renderRoute({
      stops: [
        {
          id: '1',
          location: { lat: 13.7563, lng: 100.5018 },
          name: 'Start Location',
        },
        {
          id: '2',
          location: { lat: 13.7467, lng: 100.5352 },
          name: 'End Location',
        },
      ],
    });
  };

  return (
    <div>
      <div ref={mapRef} style={{ width: '100%', height: '600px' }} />
      <button onClick={handleShowRoute} disabled={!isReady}>
        Show Route
      </button>
      <button onClick={clearRoute} disabled={!isReady}>
        Clear Route
      </button>
    </div>
  );
}

Route Map View Component

For simpler usage, use the pre-built RouteMapView component:

tsx
import { RouteMapView } from '@route-optimization/react';

function App() {
  const [route, setRoute] = useState(null);

  return (
    <RouteMapView
      apiKey="YOUR_GOOGLE_MAPS_API_KEY"
      route={route}
      mapConfig={{
        center: { lat: 13.7563, lng: 100.5018 },
        zoom: 12,
      }}
      onError={(error) => console.error('Map error:', error)}
    />
  );
}

Map Controls

Using Map Controls Hook

tsx
import { useRouteMap, useMapControls } from '@route-optimization/react';

function InteractiveMap() {
  const { mapRef, map, isReady } = useRouteMap({
    apiKey: 'YOUR_API_KEY',
  });

  const { center, zoom, bounds, setCenter, setZoom, fitBounds } = useMapControls(map);

  const handleCenterBangkok = () => {
    setCenter({ lat: 13.7563, lng: 100.5018 });
  };

  const handleZoomIn = () => {
    setZoom((zoom ?? 12) + 1);
  };

  return (
    <div>
      <div ref={mapRef} style={{ width: '100%', height: '600px' }} />

      <div className="controls">
        <p>
          Center: {center?.lat.toFixed(4)}, {center?.lng.toFixed(4)}
        </p>
        <p>Zoom: {zoom}</p>

        <button onClick={handleCenterBangkok}>Center on Bangkok</button>
        <button onClick={handleZoomIn}>Zoom In</button>
      </div>
    </div>
  );
}

Route Optimization

Basic Optimization

tsx
import { useRouteOptimization } from '@route-optimization/react';

function RouteOptimizer() {
  const { status, data, error, isLoading, isSuccess, optimize, reset } = useRouteOptimization({
    useMockMode: true, // Use mock mode for development
  });

  const handleOptimize = async () => {
    const request = {
      shipments: [
        {
          id: 'shipment-1',
          deliveryLocation: { latitude: 13.7563, longitude: 100.5018 },
        },
        {
          id: 'shipment-2',
          deliveryLocation: { latitude: 13.7467, longitude: 100.5352 },
        },
      ],
      vehicles: [
        {
          id: 'vehicle-1',
          startLocation: { latitude: 13.7563, longitude: 100.5018 },
        },
      ],
    };

    try {
      const response = await optimize(request);
      console.log('Optimization result:', response);
    } catch (err) {
      console.error('Optimization failed:', err);
    }
  };

  return (
    <div>
      <button onClick={handleOptimize} disabled={isLoading}>
        {isLoading ? 'Optimizing...' : 'Optimize Routes'}
      </button>

      {isSuccess && data && (
        <div>
          <h3>Optimization Complete!</h3>
          <p>Routes: {data.routes?.length ?? 0}</p>
          <p>Total Distance: {data.metrics?.totalDistance ?? 0} km</p>
        </div>
      )}

      {error && <div className="error">Error: {error}</div>}
    </div>
  );
}

Production Mode with Google Cloud

tsx
import { useRouteOptimization } from '@route-optimization/react';

function ProductionOptimizer() {
  const { optimize } = useRouteOptimization({
    useMockMode: false,
    projectId: 'your-google-cloud-project',
    credentials: {
      client_email: 'service-account@project.iam.gserviceaccount.com',
      private_key: process.env.GOOGLE_PRIVATE_KEY,
    },
  });

  // ... rest of component
}

Progress Tracking

tsx
import { useRouteOptimization, useOptimizationStatus } from '@route-optimization/react';

function OptimizationWithProgress() {
  const { optimize } = useRouteOptimization({ useMockMode: true });

  const {
    progress,
    step,
    setProgress,
    reset: resetProgress,
  } = useOptimizationStatus({
    onStart: () => console.log('Optimization started'),
    onSuccess: () => console.log('Optimization complete!'),
    onError: (error) => console.error('Failed:', error),
  });

  const handleOptimize = async () => {
    resetProgress();
    setProgress(0, 'Initializing...');

    // Simulate progress
    setProgress(25, 'Calculating distances...');

    const response = await optimize(request);

    setProgress(75, 'Optimizing routes...');

    if (response.success) {
      setProgress(100, 'Complete!');
    }
  };

  return (
    <div>
      <button onClick={handleOptimize}>Optimize</button>

      <div className="progress">
        <div className="progress-bar" style={{ width: `${progress}%` }} />
        <p>{step}</p>
      </div>
    </div>
  );
}

Complete Example

Combining map rendering with route optimization:

tsx
import { useState } from 'react';
import { useRouteMap, useRouteOptimization, RouteMapView } from '@route-optimization/react';
import type { Route } from '@route-optimization/core';

function CompleteApp() {
  const [route, setRoute] = useState<Route | null>(null);
  const [locations, setLocations] = useState([
    { lat: 13.7563, lng: 100.5018, name: 'Bangkok' },
    { lat: 13.7467, lng: 100.5352, name: 'Chatuchak' },
    { lat: 13.7307, lng: 100.5418, name: 'Victory Monument' },
  ]);

  const { optimize, isLoading, isSuccess } = useRouteOptimization({
    useMockMode: true,
  });

  const handleOptimize = async () => {
    const request = {
      shipments: locations.map((loc, i) => ({
        id: `shipment-${i}`,
        deliveryLocation: { latitude: loc.lat, longitude: loc.lng },
      })),
      vehicles: [
        {
          id: 'vehicle-1',
          startLocation: { latitude: locations[0].lat, longitude: locations[0].lng },
        },
      ],
    };

    const response = await optimize(request);

    if (response.success && response.routes?.[0]) {
      // Convert optimization result to Route format
      const optimizedRoute: Route = {
        stops:
          response.routes[0].stops?.map((stop, i) => ({
            id: stop.shipmentId || `stop-${i}`,
            location: {
              lat: stop.location?.latitude ?? 0,
              lng: stop.location?.longitude ?? 0,
            },
            name: locations[i]?.name ?? `Stop ${i + 1}`,
          })) ?? [],
      };

      setRoute(optimizedRoute);
    }
  };

  return (
    <div className="app">
      <div className="sidebar">
        <h2>Route Optimization</h2>

        <div className="locations">
          {locations.map((loc, i) => (
            <div key={i} className="location-item">
              {loc.name}
            </div>
          ))}
        </div>

        <button onClick={handleOptimize} disabled={isLoading}>
          {isLoading ? 'Optimizing...' : 'Optimize Route'}
        </button>

        {isSuccess && <div className="success">✓ Route optimized successfully!</div>}
      </div>

      <div className="map-container">
        <RouteMapView
          apiKey={process.env.REACT_APP_GOOGLE_MAPS_API_KEY!}
          route={route}
          mapConfig={{
            center: { lat: 13.7563, lng: 100.5018 },
            zoom: 12,
          }}
        />
      </div>
    </div>
  );
}

export default CompleteApp;

TypeScript Support

All hooks are fully typed. Import types from the packages:

tsx
import type {
  Route,
  Stop,
  MapConfig,
  OptimizationRequest,
  OptimizationResponse,
} from '@route-optimization/core';

import type {
  UseRouteMapOptions,
  UseRouteMapReturn,
  UseMapControlsReturn,
  UseRouteOptimizationResult,
} from '@route-optimization/react';

Best Practices

1. Environment Variables

Store API keys in environment variables:

env
# .env.local
REACT_APP_GOOGLE_MAPS_API_KEY=your_api_key
REACT_APP_GOOGLE_PROJECT_ID=your_project_id

2. Error Handling

Always handle errors properly:

tsx
const { optimize, error } = useRouteOptimization(config);

const handleOptimize = async () => {
  try {
    const result = await optimize(request);
    // Handle success
  } catch (err) {
    // Handle error
    console.error('Optimization failed:', err);
  }
};

3. Cleanup

Components automatically clean up when unmounted, but you can manually reset:

tsx
useEffect(() => {
  return () => {
    clearRoute();
    reset();
  };
}, []);

4. Memoization

Memoize large configuration objects:

tsx
const mapConfig = useMemo(
  () => ({
    center: { lat: 13.7563, lng: 100.5018 },
    zoom: 12,
    styles: customMapStyles,
  }),
  []
);

const { mapRef } = useRouteMap({
  apiKey,
  ...mapConfig,
});

Next Steps

Released under the MIT License.