Skip to content

Commit 8133db8

Browse files
committed
chore: Laravel 13
1 parent a7b27da commit 8133db8

File tree

8 files changed

+1547
-1195
lines changed

8 files changed

+1547
-1195
lines changed

.github/copilot-instructions.md

Lines changed: 0 additions & 440 deletions
This file was deleted.
Lines changed: 361 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,361 @@
1+
---
2+
name: inertia-react-development
3+
description: "Develops Inertia.js v2 React client-side applications. Activates when creating React pages, forms, or navigation; using <Link>, <Form>, useForm, or router; working with deferred props, prefetching, or polling; or when user mentions React with Inertia, React pages, React forms, or React navigation."
4+
license: MIT
5+
metadata:
6+
author: laravel
7+
---
8+
9+
# Inertia React Development
10+
11+
## When to Apply
12+
13+
Activate this skill when:
14+
15+
- Creating or modifying React page components for Inertia
16+
- Working with forms in React (using `<Form>` or `useForm`)
17+
- Implementing client-side navigation with `<Link>` or `router`
18+
- Using v2 features: deferred props, prefetching, WhenVisible, InfiniteScroll, once props, flash data, or polling
19+
- Building React-specific features with the Inertia protocol
20+
21+
## Documentation
22+
23+
Use `search-docs` for detailed Inertia v2 React patterns and documentation.
24+
25+
## Basic Usage
26+
27+
### Page Components Location
28+
29+
React page components should be placed in the `resources/js/Pages` directory.
30+
31+
### Page Component Structure
32+
33+
<!-- Basic React Page Component -->
34+
```react
35+
export default function UsersIndex({ users }) {
36+
return (
37+
<div>
38+
<h1>Users</h1>
39+
<ul>
40+
{users.map(user => <li key={user.id}>{user.name}</li>)}
41+
</ul>
42+
</div>
43+
)
44+
}
45+
```
46+
47+
## Client-Side Navigation
48+
49+
### Basic Link Component
50+
51+
Use `<Link>` for client-side navigation instead of traditional `<a>` tags:
52+
53+
<!-- Inertia React Navigation -->
54+
```react
55+
import { Link, router } from '@inertiajs/react'
56+
57+
<Link href="/">Home</Link>
58+
<Link href="/users">Users</Link>
59+
<Link href={`/users/${user.id}`}>View User</Link>
60+
```
61+
62+
### Link with Method
63+
64+
<!-- Link with POST Method -->
65+
```react
66+
import { Link } from '@inertiajs/react'
67+
68+
<Link href="/logout" method="post" as="button">
69+
Logout
70+
</Link>
71+
```
72+
73+
### Prefetching
74+
75+
Prefetch pages to improve perceived performance:
76+
77+
<!-- Prefetch on Hover -->
78+
```react
79+
import { Link } from '@inertiajs/react'
80+
81+
<Link href="/users" prefetch>
82+
Users
83+
</Link>
84+
```
85+
86+
### Programmatic Navigation
87+
88+
<!-- Router Visit -->
89+
```react
90+
import { router } from '@inertiajs/react'
91+
92+
function handleClick() {
93+
router.visit('/users')
94+
}
95+
96+
// Or with options
97+
router.visit('/users', {
98+
method: 'post',
99+
data: { name: 'John' },
100+
onSuccess: () => console.log('Success!'),
101+
})
102+
```
103+
104+
## Form Handling
105+
106+
### Form Component (Recommended)
107+
108+
The recommended way to build forms is with the `<Form>` component:
109+
110+
<!-- Form Component Example -->
111+
```react
112+
import { Form } from '@inertiajs/react'
113+
114+
export default function CreateUser() {
115+
return (
116+
<Form action="/users" method="post">
117+
{({ errors, processing, wasSuccessful }) => (
118+
<>
119+
<input type="text" name="name" />
120+
{errors.name && <div>{errors.name}</div>}
121+
122+
<input type="email" name="email" />
123+
{errors.email && <div>{errors.email}</div>}
124+
125+
<button type="submit" disabled={processing}>
126+
{processing ? 'Creating...' : 'Create User'}
127+
</button>
128+
129+
{wasSuccessful && <div>User created!</div>}
130+
</>
131+
)}
132+
</Form>
133+
)
134+
}
135+
```
136+
137+
### Form Component With All Props
138+
139+
<!-- Form Component Full Example -->
140+
```react
141+
import { Form } from '@inertiajs/react'
142+
143+
<Form action="/users" method="post">
144+
{({
145+
errors,
146+
hasErrors,
147+
processing,
148+
progress,
149+
wasSuccessful,
150+
recentlySuccessful,
151+
clearErrors,
152+
resetAndClearErrors,
153+
defaults,
154+
isDirty,
155+
reset,
156+
submit
157+
}) => (
158+
<>
159+
<input type="text" name="name" defaultValue={defaults.name} />
160+
{errors.name && <div>{errors.name}</div>}
161+
162+
<button type="submit" disabled={processing}>
163+
{processing ? 'Saving...' : 'Save'}
164+
</button>
165+
166+
{progress && (
167+
<progress value={progress.percentage} max="100">
168+
{progress.percentage}%
169+
</progress>
170+
)}
171+
172+
{wasSuccessful && <div>Saved!</div>}
173+
</>
174+
)}
175+
</Form>
176+
```
177+
178+
### Form Component Reset Props
179+
180+
The `<Form>` component supports automatic resetting:
181+
182+
- `resetOnError` - Reset form data when the request fails
183+
- `resetOnSuccess` - Reset form data when the request succeeds
184+
- `setDefaultsOnSuccess` - Update default values on success
185+
186+
Use the `search-docs` tool with a query of `form component resetting` for detailed guidance.
187+
188+
<!-- Form with Reset Props -->
189+
```react
190+
import { Form } from '@inertiajs/react'
191+
192+
<Form
193+
action="/users"
194+
method="post"
195+
resetOnSuccess
196+
setDefaultsOnSuccess
197+
>
198+
{({ errors, processing, wasSuccessful }) => (
199+
<>
200+
<input type="text" name="name" />
201+
{errors.name && <div>{errors.name}</div>}
202+
203+
<button type="submit" disabled={processing}>
204+
Submit
205+
</button>
206+
</>
207+
)}
208+
</Form>
209+
```
210+
211+
Forms can also be built using the `useForm` helper for more programmatic control. Use the `search-docs` tool with a query of `useForm helper` for guidance.
212+
213+
### `useForm` Hook
214+
215+
For more programmatic control or to follow existing conventions, use the `useForm` hook:
216+
217+
<!-- useForm Hook Example -->
218+
```react
219+
import { useForm } from '@inertiajs/react'
220+
221+
export default function CreateUser() {
222+
const { data, setData, post, processing, errors, reset } = useForm({
223+
name: '',
224+
email: '',
225+
password: '',
226+
})
227+
228+
function submit(e) {
229+
e.preventDefault()
230+
post('/users', {
231+
onSuccess: () => reset('password'),
232+
})
233+
}
234+
235+
return (
236+
<form onSubmit={submit}>
237+
<input
238+
type="text"
239+
value={data.name}
240+
onChange={e => setData('name', e.target.value)}
241+
/>
242+
{errors.name && <div>{errors.name}</div>}
243+
244+
<input
245+
type="email"
246+
value={data.email}
247+
onChange={e => setData('email', e.target.value)}
248+
/>
249+
{errors.email && <div>{errors.email}</div>}
250+
251+
<input
252+
type="password"
253+
value={data.password}
254+
onChange={e => setData('password', e.target.value)}
255+
/>
256+
{errors.password && <div>{errors.password}</div>}
257+
258+
<button type="submit" disabled={processing}>
259+
Create User
260+
</button>
261+
</form>
262+
)
263+
}
264+
```
265+
266+
## Inertia v2 Features
267+
268+
### Deferred Props
269+
270+
Use deferred props to load data after initial page render:
271+
272+
<!-- Deferred Props with Empty State -->
273+
```react
274+
export default function UsersIndex({ users }) {
275+
// users will be undefined initially, then populated
276+
return (
277+
<div>
278+
<h1>Users</h1>
279+
{!users ? (
280+
<div className="animate-pulse">
281+
<div className="h-4 bg-gray-200 rounded w-3/4 mb-2"></div>
282+
<div className="h-4 bg-gray-200 rounded w-1/2"></div>
283+
</div>
284+
) : (
285+
<ul>
286+
{users.map(user => (
287+
<li key={user.id}>{user.name}</li>
288+
))}
289+
</ul>
290+
)}
291+
</div>
292+
)
293+
}
294+
```
295+
296+
### Polling
297+
298+
Automatically refresh data at intervals:
299+
300+
<!-- Polling Example -->
301+
```react
302+
import { router } from '@inertiajs/react'
303+
import { useEffect } from 'react'
304+
305+
export default function Dashboard({ stats }) {
306+
useEffect(() => {
307+
const interval = setInterval(() => {
308+
router.reload({ only: ['stats'] })
309+
}, 5000) // Poll every 5 seconds
310+
311+
return () => clearInterval(interval)
312+
}, [])
313+
314+
return (
315+
<div>
316+
<h1>Dashboard</h1>
317+
<div>Active Users: {stats.activeUsers}</div>
318+
</div>
319+
)
320+
}
321+
```
322+
323+
### WhenVisible
324+
325+
Lazy-load a prop when an element scrolls into view. Useful for deferring expensive data that sits below the fold:
326+
327+
<!-- WhenVisible Example -->
328+
```react
329+
import { WhenVisible } from '@inertiajs/react'
330+
331+
export default function Dashboard({ stats }) {
332+
return (
333+
<div>
334+
<h1>Dashboard</h1>
335+
336+
{/* stats prop is loaded only when this section scrolls into view */}
337+
<WhenVisible data="stats" buffer={200} fallback={<div className="animate-pulse">Loading stats...</div>}>
338+
{({ fetching }) => (
339+
<div>
340+
<p>Total Users: {stats.total_users}</p>
341+
<p>Revenue: {stats.revenue}</p>
342+
{fetching && <span>Refreshing...</span>}
343+
</div>
344+
)}
345+
</WhenVisible>
346+
</div>
347+
)
348+
}
349+
```
350+
351+
## Server-Side Patterns
352+
353+
Server-side patterns (Inertia::render, props, middleware) are covered in inertia-laravel guidelines.
354+
355+
## Common Pitfalls
356+
357+
- Using traditional `<a>` links instead of Inertia's `<Link>` component (breaks SPA behavior)
358+
- Forgetting to add loading states (skeleton screens) when using deferred props
359+
- Not handling the `undefined` state of deferred props before data loads
360+
- Using `<form>` without preventing default submission (use `<Form>` component or `e.preventDefault()`)
361+
- Forgetting to check if `<Form>` component is available in your Inertia version

0 commit comments

Comments
 (0)