> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/tighten/ziggy/llms.txt
> Use this file to discover all available pages before exploring further.

# React

> Using Ziggy with React applications via the useRoute hook

## Installation

Ziggy includes a `useRoute()` hook that makes it easy to use the `route()` helper in your React components.

### Basic Setup with @routes

If you're using the `@routes` Blade directive, Ziggy's config is available globally. Simply import and use the hook:

```jsx theme={null}
import React from 'react';
import { useRoute } from 'ziggy-js';

export default function PostsLink() {
    const route = useRoute();

    return <a href={route('posts.index')}>All Posts</a>;
}
```

### Setup Without @routes

If you're not using `@routes`, import Ziggy's configuration and pass it to `useRoute()`:

```jsx theme={null}
import React from 'react';
import { useRoute } from 'ziggy-js';
import { Ziggy } from './ziggy.js'; // Generated by php artisan ziggy:generate

export default function PostsLink() {
    const route = useRoute(Ziggy);

    return <a href={route('posts.index')}>All Posts</a>;
}
```

## Making Config Global

To avoid passing `Ziggy` to every `useRoute()` call, make it available globally:

```js theme={null}
// app.js or index.js
import { Ziggy } from './ziggy.js';

// Make Ziggy globally available
globalThis.Ziggy = Ziggy;
```

Now you can use `useRoute()` without passing the config:

```jsx theme={null}
import { useRoute } from 'ziggy-js';

export default function Navigation() {
    const route = useRoute(); // No config needed

    return (
        <nav>
            <a href={route('home')}>Home</a>
            <a href={route('about')}>About</a>
        </nav>
    );
}
```

## Basic Usage

### Simple Links

```jsx theme={null}
import React from 'react';
import { useRoute } from 'ziggy-js';

export default function Navigation() {
    const route = useRoute();

    return (
        <nav className="main-nav">
            <a href={route('home')} className="nav-link">Home</a>
            <a href={route('posts.index')} className="nav-link">Blog</a>
            <a href={route('contact')} className="nav-link">Contact</a>
        </nav>
    );
}
```

### Links with Parameters

```jsx theme={null}
import React from 'react';
import { useRoute } from 'ziggy-js';

export default function PostCard({ post }) {
    const route = useRoute();

    return (
        <article>
            <h2>{post.title}</h2>
            <p>{post.excerpt}</p>
            <a href={route('posts.show', { post: post.id })}>
                Read more →
            </a>
        </article>
    );
}
```

### Dynamic Lists

```jsx theme={null}
import React from 'react';
import { useRoute } from 'ziggy-js';

export default function PostList({ posts }) {
    const route = useRoute();

    return (
        <ul>
            {posts.map(post => (
                <li key={post.id}>
                    <a href={route('posts.show', { post: post })}>
                        {post.title}
                    </a>
                </li>
            ))}
        </ul>
    );
}
```

## React Router Integration

Use Ziggy with React Router for client-side navigation:

```jsx theme={null}
import React from 'react';
import { Link } from 'react-router-dom';
import { useRoute } from 'ziggy-js';

export default function Navigation() {
    const route = useRoute();

    return (
        <nav>
            <Link to={route('home', [], false)}>Home</Link>
            <Link to={route('posts.index', [], false)}>Blog</Link>
            <Link to={route('about', [], false)}>About</Link>
        </nav>
    );
}
```

<Note>
  Pass `false` as the third argument to `route()` to generate relative URLs without the domain.
</Note>

## Form Handling

### POST Requests with axios

```jsx theme={null}
import React, { useState } from 'react';
import { useRoute } from 'ziggy-js';
import axios from 'axios';

export default function CreatePost() {
    const route = useRoute();
    const [post, setPost] = useState({ title: '', body: '' });
    const [loading, setLoading] = useState(false);

    const handleSubmit = async (e) => {
        e.preventDefault();
        setLoading(true);

        try {
            const response = await axios.post(route('posts.store'), post);
            console.log('Post created:', response.data);
            // Redirect to the new post
            window.location.href = route('posts.show', { post: response.data.id });
        } catch (error) {
            console.error('Error creating post:', error);
        } finally {
            setLoading(false);
        }
    };

    return (
        <form onSubmit={handleSubmit}>
            <input
                type="text"
                value={post.title}
                onChange={(e) => setPost({ ...post, title: e.target.value })}
                placeholder="Post title"
                required
            />
            <textarea
                value={post.body}
                onChange={(e) => setPost({ ...post, body: e.target.value })}
                placeholder="Post content"
                required
            />
            <button type="submit" disabled={loading}>
                {loading ? 'Creating...' : 'Create Post'}
            </button>
        </form>
    );
}
```

### Update Requests

```jsx theme={null}
import React, { useState } from 'react';
import { useRoute } from 'ziggy-js';
import axios from 'axios';

export default function EditPost({ initialPost }) {
    const route = useRoute();
    const [post, setPost] = useState(initialPost);

    const handleUpdate = async (e) => {
        e.preventDefault();

        await axios.put(
            route('posts.update', { post: post.id }),
            post
        );

        alert('Post updated successfully!');
    };

    const handleDelete = async () => {
        if (!confirm('Are you sure?')) return;

        await axios.delete(route('posts.destroy', { post: post.id }));
        window.location.href = route('posts.index');
    };

    return (
        <form onSubmit={handleUpdate}>
            <input
                type="text"
                value={post.title}
                onChange={(e) => setPost({ ...post, title: e.target.value })}
            />
            <textarea
                value={post.body}
                onChange={(e) => setPost({ ...post, body: e.target.value })}
            />
            <button type="submit">Update Post</button>
            <button type="button" onClick={handleDelete}>
                Delete Post
            </button>
        </form>
    );
}
```

## Data Fetching

### Using fetch API

```jsx theme={null}
import React, { useState, useEffect } from 'react';
import { useRoute } from 'ziggy-js';

export default function Post({ postId }) {
    const route = useRoute();
    const [post, setPost] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        async function fetchPost() {
            try {
                const response = await fetch(
                    route('api.posts.show', { post: postId })
                );
                const data = await response.json();
                setPost(data);
            } catch (err) {
                setError(err.message);
            } finally {
                setLoading(false);
            }
        }

        fetchPost();
    }, [postId]);

    if (loading) return <div>Loading...</div>;
    if (error) return <div>Error: {error}</div>;

    return (
        <article>
            <h1>{post.title}</h1>
            <div>{post.body}</div>
        </article>
    );
}
```

### Custom Hook for Data Fetching

```jsx theme={null}
import { useState, useEffect } from 'react';
import { useRoute } from 'ziggy-js';

function useLaravelRoute(routeName, params) {
    const route = useRoute();
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        async function fetchData() {
            try {
                const response = await fetch(route(routeName, params));
                const json = await response.json();
                setData(json);
            } catch (err) {
                setError(err);
            } finally {
                setLoading(false);
            }
        }

        fetchData();
    }, [routeName, JSON.stringify(params)]);

    return { data, loading, error };
}

// Usage
export default function Posts() {
    const { data: posts, loading, error } = useLaravelRoute('api.posts.index');

    if (loading) return <div>Loading...</div>;
    if (error) return <div>Error loading posts</div>;

    return (
        <ul>
            {posts.map(post => (
                <li key={post.id}>{post.title}</li>
            ))}
        </ul>
    );
}
```

## TypeScript Support

### Basic TypeScript Usage

```tsx theme={null}
import React from 'react';
import { useRoute } from 'ziggy-js';
import type { RouteUrl } from 'ziggy-js';

interface Post {
    id: number;
    title: string;
    body: string;
}

interface PostCardProps {
    post: Post;
}

export default function PostCard({ post }: PostCardProps) {
    const route = useRoute();
    const postUrl: RouteUrl = route('posts.show', { post: post.id });

    return (
        <article>
            <h2>{post.title}</h2>
            <a href={postUrl}>Read more</a>
        </article>
    );
}
```

### With Generated Types

First, generate Ziggy's TypeScript definitions:

```bash theme={null}
php artisan ziggy:generate --types
```

Now you get full autocomplete for route names and parameters:

```tsx theme={null}
import React from 'react';
import { useRoute } from 'ziggy-js';

export default function Navigation() {
    const route = useRoute();

    // TypeScript knows 'posts.show' requires a 'post' parameter
    const url = route('posts.show', { post: 1 }); // ✓ Valid
    
    // TypeScript will error on invalid route names
    // const invalid = route('invalid.route'); // ✗ Type error

    return <a href={url}>View Post</a>;
}
```

### Strict Type Checking

Enable strict route name checking:

```ts theme={null}
// ziggy.d.ts
declare module 'ziggy-js' {
    interface TypeConfig {
        strictRouteNames: true;
    }
}

export {};
```

## Hook Implementation

The `useRoute()` hook is implemented as follows:

```js theme={null}
export function useRoute(defaultConfig) {
    if (
        !defaultConfig &&
        !globalThis.Ziggy &&
        typeof Ziggy === 'undefined' &&
        !document.getElementById('ziggy-routes-json')
    ) {
        throw new Error(
            'Ziggy error: missing configuration. Ensure that a `Ziggy` variable is defined globally or pass a config object into the useRoute hook.',
        );
    }

    return (name, params, absolute, config = defaultConfig) =>
        route(name, params, absolute, config);
}
```

The hook returns a version of `route()` that automatically uses the config you passed to `useRoute()`, or falls back to the global `Ziggy` variable.

## Server-Side Rendering (SSR)

For SSR frameworks like Next.js, ensure Ziggy's config is available on both server and client:

```jsx theme={null}
// pages/_app.js
import { Ziggy } from '../ziggy.js';

if (typeof window === 'undefined') {
    // Server-side
    globalThis.Ziggy = Ziggy;
} else {
    // Client-side
    window.Ziggy = Ziggy;
}

function MyApp({ Component, pageProps }) {
    return <Component {...pageProps} />;
}

export default MyApp;
```

## Troubleshooting

### "Missing configuration" error

This error means `useRoute()` can't find Ziggy's config. Either:

1. Pass the config directly: `useRoute(Ziggy)`
2. Make it global: `globalThis.Ziggy = Ziggy`
3. Use the `@routes` Blade directive

### Routes not updating after changes

If you're using `ziggy:generate`, re-run the command after changing routes:

```bash theme={null}
php artisan ziggy:generate
```

### TypeScript errors with route names

Generate type definitions:

```bash theme={null}
php artisan ziggy:generate --types
```

## Next Steps

<CardGroup cols={2}>
  <Card title="TypeScript" icon="code" href="/typescript">
    Set up full type safety and autocompletion
  </Card>

  <Card title="Vue" icon="vuejs" href="/vue">
    Use Ziggy with Vue instead
  </Card>

  <Card title="Route Helper" icon="route" href="/route-function">
    Learn all route() function capabilities
  </Card>

  <Card title="JavaScript Frameworks" icon="js" href="/javascript-frameworks">
    General framework integration guide
  </Card>
</CardGroup>
