---
source_hash: "40665589"
title: "Chapter 3: Utility Hooks"
weight: 600
---

# Chapter 3: Utility Hooks

SmartCommon provides utility hooks for common tasks.

## useNavigation

Programmatic navigation with React Router.

```javascript
import { useNavigation } from '@cap-rel/smartcommon';

function MyComponent() {
    const nav = useNavigation();

    return (
        <div>
            {/* Navigate to route */}
            <button onClick={() => nav.navigate('/products')}>
                Products
            </button>

            {/* Navigate with parameter */}
            <button onClick={() => nav.navigate(`/products/${id}`)}>
                Details
            </button>

            {/* Go back */}
            <button onClick={() => nav.navigate(-1)}>
                Back
            </button>

            {/* Replace (no history) */}
            <button onClick={() => nav.replace('/login')}>
                Login
            </button>
        </div>
    );
}
```

## useLibConfig

Access application configuration.

```javascript
import { useLibConfig } from '@cap-rel/smartcommon';

function DebugInfo() {
    const config = useLibConfig();

    if (!config.debug) return null;

    return (
        <div className="debug-panel">
            <p>API URL: {config.api.prefixUrl}</p>
            <p>Mode: {config.debug ? 'Debug' : 'Production'}</p>
        </div>
    );
}
```

## useIntl

Date and number formatting with the Intl API.

### Date Formatting

```javascript
import { useIntl } from '@cap-rel/smartcommon';

function EventCard({ event }) {
    const intl = useIntl();

    // Default format
    const dateFormatted = intl.DateTimeFormat(event.date);
    // "03/15/2024, 2:30:00 PM"

    // Custom format
    const dateOnly = intl.DateTimeFormat(event.date, 'fr-FR', {
        year: 'numeric',
        month: 'long',
        day: 'numeric'
    });
    // "15 mars 2024"

    // Time only
    const timeOnly = intl.DateTimeFormat(event.date, 'fr-FR', {
        hour: '2-digit',
        minute: '2-digit'
    });
    // "2:30 PM"

    return (
        <div>
            <h3>{event.title}</h3>
            <p>On {dateOnly} at {timeOnly}</p>
        </div>
    );
}
```

### Number Formatting

```javascript
function PriceDisplay({ price, currency = 'EUR' }) {
    const intl = useIntl();

    const formatted = intl.NumberFormat(price, 'fr-FR', {
        style: 'currency',
        currency: currency
    });
    // "29.99 €"

    return <span>{formatted}</span>;
}

function PercentDisplay({ value }) {
    const intl = useIntl();

    const formatted = intl.NumberFormat(value, 'fr-FR', {
        style: 'percent',
        minimumFractionDigits: 1
    });
    // "15.5%"

    return <span>{formatted}</span>;
}
```

## useWindow

Browser window information.

```javascript
import { useWindow } from '@cap-rel/smartcommon';

function ResponsiveLayout({ children }) {
    const { orientation, windowDimension, darkMode } = useWindow();

    // orientation: 'portrait' or 'landscape'
    // windowDimension: { w, h }
    // darkMode: boolean

    if (windowDimension.w < 768) {
        return <MobileLayout>{children}</MobileLayout>;
    }

    if (windowDimension.w < 1024) {
        return <TabletLayout>{children}</TabletLayout>;
    }

    return <DesktopLayout>{children}</DesktopLayout>;
}

function WindowInfo() {
    const { windowDimension } = useWindow();

    return <p>Window: {windowDimension.w} x {windowDimension.h}</p>;
}
```

## useFile

File manipulation utilities.

### Resize Image

```javascript
import { useFile } from '@cap-rel/smartcommon';

function ImageUploader({ onUpload }) {
    const { resizeImage } = useFile();

    const handleFileChange = async (e) => {
        const file = e.target.files[0];
        if (!file) return;

        // Resize before upload
        const base64 = await resizeImage(file, {
            maxWidth: 1920,
            maxHeight: 1080,
            quality: 85
        });

        // base64 = "data:image/jpeg;base64,..."
        onUpload(base64);
    };

    return (
        <input
            type="file"
            accept="image/*"
            onChange={handleFileChange}
        />
    );
}
```

## useDb

IndexedDB database via Dexie for local storage of large amounts of data.

### Configuration

```javascript
import { useDb } from '@cap-rel/smartcommon';

const db = useDb({
    name: 'myApp',
    version: 1,
    stores: {
        items: 'id++, name, category, createdAt',
        logs: 'id++, action, timestamp'
    },
    debug: true
});
```

### CRUD Operations

```javascript
function ItemsManager() {
    const db = useDb({
        name: 'myApp',
        version: 1,
        stores: {
            items: 'id++, name, category'
        }
    });

    // Create
    const addItem = async (item) => {
        const id = await db.items.add(item);
        console.log('Item created with id:', id);
        return id;
    };

    // Read all
    const getAllItems = async () => {
        return db.items.toArray();
    };

    // Read one
    const getItem = async (id) => {
        return db.items.get(id);
    };

    // Update
    const updateItem = async (id, changes) => {
        await db.items.update(id, changes);
    };

    // Delete
    const deleteItem = async (id) => {
        await db.items.delete(id);
    };

    // ...
}
```

### Advanced Queries

```javascript
// Filter by value
const electronics = await db.items
    .where('category')
    .equals('electronics')
    .toArray();

// Filter by range
const expensiveItems = await db.items
    .where('price')
    .above(100)
    .toArray();

// Sort
const sorted = await db.items
    .orderBy('createdAt')
    .reverse()
    .toArray();

// Limit
const first10 = await db.items
    .limit(10)
    .toArray();

// Count
const count = await db.items.count();

// Text search
const matching = await db.items
    .filter(item => item.name.includes('test'))
    .toArray();
```

### Example: Offline Mode

```javascript
import { useEffect } from 'react';
import { useApi, useDb, useStates } from '@cap-rel/smartcommon';

function OfflineCapableList() {
    const api = useApi();
    const db = useDb({
        name: 'myApp',
        version: 1,
        stores: { items: 'id, name, synced' }
    });

    const st = useStates({
        initialStates: { items: [], loading: true }
    });

    useEffect(() => {
        loadItems();
    }, []);

    const loadItems = async () => {
        try {
            // Try to load from API
            const data = await api.private.get('items').json();

            // Save locally
            await db.items.clear();
            await db.items.bulkAdd(data.map(i => ({ ...i, synced: true })));

            st.set('items', data);
        } catch (err) {
            // On network error, load from IndexedDB
            console.log('Offline mode - loading local');
            const localItems = await db.items.toArray();
            st.set('items', localItems);
        } finally {
            st.set('loading', false);
        }
    };

    const addItem = async (item) => {
        // Save locally first
        const id = await db.items.add({ ...item, synced: false });

        // Update UI
        st.set('items', [...st.get('items'), { ...item, id }]);

        // Try to sync
        try {
            const result = await api.private.post('items', { json: item }).json();
            await db.items.update(id, { ...result, synced: true });
        } catch (err) {
            console.log('Sync failed, will retry later');
        }
    };

    // ...
}
```

## useAnimation

Animation management with Framer Motion.

```javascript
import { useAnimation } from '@cap-rel/smartcommon';
import { motion } from 'framer-motion';

function AnimatedList({ items }) {
    const { start } = useAnimation();

    return (
        <div>
            {items.map((item, index) => (
                <motion.div
                    key={item.id}
                    initial={{ opacity: 0, y: 20 }}
                    animate={start ? { opacity: 1, y: 0 } : {}}
                    transition={{ delay: index * 0.1 }}
                >
                    {item.name}
                </motion.div>
            ))}
        </div>
    );
}
```

## useListDnD

Drag and drop for reordering lists.

```javascript
import { useListDnD } from '@cap-rel/smartcommon';

function SortableList({ initialItems, onReorder }) {
    const {
        items,
        onDragStart,
        onDragOver,
        onDrop
    } = useListDnD({
        initialItems,
        onReorder: (newItems) => {
            console.log('New order:', newItems);
            onReorder(newItems);
        }
    });

    return (
        <ul>
            {items.map((item, index) => (
                <li
                    key={item.id}
                    draggable
                    onDragStart={(e) => onDragStart(e, index)}
                    onDragOver={onDragOver}
                    onDrop={(e) => onDrop(e, index)}
                >
                    {item.name}
                </li>
            ))}
        </ul>
    );
}
```

## Summary Table

| Hook | Usage | Example |
| --- | --- | --- |
| useNavigation | Navigation | nav.navigate('/products') |
| useLibConfig | App config | config.debug |
| useIntl | Formatting | intl.DateTimeFormat(date) |
| useWindow | Responsive | orientation, windowDimension, scroll, darkMode |
| useFile | Files | resizeImage(file, options) |
| useDb | IndexedDB | db.items.add(item) |
| useAnimation | Animations | start (boolean) |
| useListDnD | Drag & drop | onDragStart, onDragOver, onDrop |

## Key Points to Remember

1. **useNavigation** for programmatic navigation
2. **useIntl** for localized formatting
3. **useWindow** for responsive design
4. **useFile** for image processing
5. **useDb** for local storage (offline)

[Previous Chapter](/training/module7-smartcommon-hooks/etat) | [Back to Module](/training/module7-smartcommon-hooks) | [Next Module: Backend API ->](/training/module8-backend-api)
