260322:1648 Correct Coresspondence / Doing RFA / Correct CI
This commit is contained in:
@@ -12,33 +12,33 @@ Client components **cannot** be async functions. Only Server Components can be a
|
||||
|
||||
```tsx
|
||||
// Bad: async client component
|
||||
'use client'
|
||||
'use client';
|
||||
export default async function UserProfile() {
|
||||
const user = await getUser() // Cannot await in client component
|
||||
return <div>{user.name}</div>
|
||||
const user = await getUser(); // Cannot await in client component
|
||||
return <div>{user.name}</div>;
|
||||
}
|
||||
|
||||
// Good: Remove async, fetch data in parent server component
|
||||
// page.tsx (server component - no 'use client')
|
||||
export default async function Page() {
|
||||
const user = await getUser()
|
||||
return <UserProfile user={user} />
|
||||
const user = await getUser();
|
||||
return <UserProfile user={user} />;
|
||||
}
|
||||
|
||||
// UserProfile.tsx (client component)
|
||||
'use client'
|
||||
('use client');
|
||||
export function UserProfile({ user }: { user: User }) {
|
||||
return <div>{user.name}</div>
|
||||
return <div>{user.name}</div>;
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
// Bad: async arrow function client component
|
||||
'use client'
|
||||
'use client';
|
||||
const Dashboard = async () => {
|
||||
const data = await fetchDashboard()
|
||||
return <div>{data}</div>
|
||||
}
|
||||
const data = await fetchDashboard();
|
||||
return <div>{data}</div>;
|
||||
};
|
||||
|
||||
// Good: Fetch in server component, pass data down
|
||||
```
|
||||
@@ -48,6 +48,7 @@ const Dashboard = async () => {
|
||||
Props passed from Server → Client must be JSON-serializable.
|
||||
|
||||
**Detect:** Server component passes these to a client component:
|
||||
|
||||
- Functions (except Server Actions with `'use server'`)
|
||||
- `Date` objects
|
||||
- `Map`, `Set`, `WeakMap`, `WeakSet`
|
||||
@@ -59,16 +60,16 @@ Props passed from Server → Client must be JSON-serializable.
|
||||
// Bad: Function prop
|
||||
// page.tsx (server)
|
||||
export default function Page() {
|
||||
const handleClick = () => console.log('clicked')
|
||||
return <ClientButton onClick={handleClick} />
|
||||
const handleClick = () => console.log('clicked');
|
||||
return <ClientButton onClick={handleClick} />;
|
||||
}
|
||||
|
||||
// Good: Define function inside client component
|
||||
// ClientButton.tsx
|
||||
'use client'
|
||||
('use client');
|
||||
export function ClientButton() {
|
||||
const handleClick = () => console.log('clicked')
|
||||
return <button onClick={handleClick}>Click</button>
|
||||
const handleClick = () => console.log('clicked');
|
||||
return <button onClick={handleClick}>Click</button>;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -76,28 +77,28 @@ export function ClientButton() {
|
||||
// Bad: Date object (silently becomes string, then crashes)
|
||||
// page.tsx (server)
|
||||
export default async function Page() {
|
||||
const post = await getPost()
|
||||
return <PostCard createdAt={post.createdAt} /> // Date object
|
||||
const post = await getPost();
|
||||
return <PostCard createdAt={post.createdAt} />; // Date object
|
||||
}
|
||||
|
||||
// PostCard.tsx (client) - will crash on .getFullYear()
|
||||
'use client'
|
||||
('use client');
|
||||
export function PostCard({ createdAt }: { createdAt: Date }) {
|
||||
return <span>{createdAt.getFullYear()}</span> // Runtime error!
|
||||
return <span>{createdAt.getFullYear()}</span>; // Runtime error!
|
||||
}
|
||||
|
||||
// Good: Serialize to string on server
|
||||
// page.tsx (server)
|
||||
export default async function Page() {
|
||||
const post = await getPost()
|
||||
return <PostCard createdAt={post.createdAt.toISOString()} />
|
||||
const post = await getPost();
|
||||
return <PostCard createdAt={post.createdAt.toISOString()} />;
|
||||
}
|
||||
|
||||
// PostCard.tsx (client)
|
||||
'use client'
|
||||
('use client');
|
||||
export function PostCard({ createdAt }: { createdAt: string }) {
|
||||
const date = new Date(createdAt)
|
||||
return <span>{date.getFullYear()}</span>
|
||||
const date = new Date(createdAt);
|
||||
return <span>{date.getFullYear()}</span>;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -127,33 +128,33 @@ Functions marked with `'use server'` CAN be passed to client components.
|
||||
```tsx
|
||||
// Valid: Server Action can be passed
|
||||
// actions.ts
|
||||
'use server'
|
||||
'use server';
|
||||
export async function submitForm(formData: FormData) {
|
||||
// server-side logic
|
||||
}
|
||||
|
||||
// page.tsx (server)
|
||||
import { submitForm } from './actions'
|
||||
import { submitForm } from './actions';
|
||||
export default function Page() {
|
||||
return <ClientForm onSubmit={submitForm} /> // OK!
|
||||
return <ClientForm onSubmit={submitForm} />; // OK!
|
||||
}
|
||||
|
||||
// ClientForm.tsx (client)
|
||||
'use client'
|
||||
('use client');
|
||||
export function ClientForm({ onSubmit }: { onSubmit: (data: FormData) => Promise<void> }) {
|
||||
return <form action={onSubmit}>...</form>
|
||||
return <form action={onSubmit}>...</form>;
|
||||
}
|
||||
```
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Pattern | Valid? | Fix |
|
||||
|---------|--------|-----|
|
||||
| `'use client'` + `async function` | No | Fetch in server parent, pass data |
|
||||
| Pass `() => {}` to client | No | Define in client or use server action |
|
||||
| Pass `new Date()` to client | No | Use `.toISOString()` |
|
||||
| Pass `new Map()` to client | No | Convert to object/array |
|
||||
| Pass class instance to client | No | Pass plain object |
|
||||
| Pass server action to client | Yes | - |
|
||||
| Pass `string/number/boolean` | Yes | - |
|
||||
| Pass plain object/array | Yes | - |
|
||||
| Pattern | Valid? | Fix |
|
||||
| --------------------------------- | ------ | ------------------------------------- |
|
||||
| `'use client'` + `async function` | No | Fetch in server parent, pass data |
|
||||
| Pass `() => {}` to client | No | Define in client or use server action |
|
||||
| Pass `new Date()` to client | No | Use `.toISOString()` |
|
||||
| Pass `new Map()` to client | No | Convert to object/array |
|
||||
| Pass class instance to client | No | Pass plain object |
|
||||
| Pass server action to client | Yes | - |
|
||||
| Pass `string/number/boolean` | Yes | - |
|
||||
| Pass plain object/array | Yes | - |
|
||||
|
||||
Reference in New Issue
Block a user