- Add React Router with theme browser, theme detail, and layout detail pages - Implement manifest-based theme discovery for better performance - Add Welcome component as home page with feature overview - Fix layout and styling issues with proper CSS centering - Implement introspective theme browsing (dynamically discover colors/variables) - Add layout preview system with iframe scaling - Create comprehensive theme detail page with color palette display - Fix TypeScript errors and build issues - Remove hardcoded theme assumptions in favor of dynamic discovery 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
311 lines
7.0 KiB
Markdown
311 lines
7.0 KiB
Markdown
# React 19 Guidelines & Best Practices
|
|
|
|
*Based on [React 19 Release Blog](https://react.dev/blog/2024/12/05/react-19)*
|
|
|
|
## Core Philosophy
|
|
**"React 19 provides powerful tools to create more responsive, efficient web applications with simplified state management and rendering strategies."**
|
|
|
|
## Key New Features
|
|
|
|
### 1. Actions
|
|
Actions simplify data mutations and state updates by automatically managing:
|
|
- **Pending states** - know when operations are in progress
|
|
- **Optimistic updates** - update UI before server confirms
|
|
- **Error handling** - graceful error recovery
|
|
- **Form submissions** - streamlined form processing
|
|
|
|
```jsx
|
|
// Example: Using Actions for form submission
|
|
function UpdateName({ name, updateName }) {
|
|
const [isPending, startTransition] = useTransition();
|
|
|
|
return (
|
|
<form action={updateName}>
|
|
<input name="name" defaultValue={name} />
|
|
<button type="submit" disabled={isPending}>
|
|
{isPending ? 'Updating...' : 'Update'}
|
|
</button>
|
|
</form>
|
|
);
|
|
}
|
|
```
|
|
|
|
### 2. New Hooks
|
|
|
|
#### `useActionState`
|
|
Simplifies action handling with built-in state management:
|
|
```jsx
|
|
function MyComponent() {
|
|
const [state, formAction] = useActionState(actionFunction, initialState);
|
|
|
|
return (
|
|
<form action={formAction}>
|
|
{/* Form elements */}
|
|
</form>
|
|
);
|
|
}
|
|
```
|
|
|
|
#### `useOptimistic`
|
|
Enables optimistic UI updates for responsive user experience:
|
|
```jsx
|
|
function TodoList({ todos, addTodo }) {
|
|
const [optimisticTodos, addOptimisticTodo] = useOptimistic(
|
|
todos,
|
|
(state, newTodo) => [...state, { ...newTodo, sending: true }]
|
|
);
|
|
|
|
async function formAction(formData) {
|
|
addOptimisticTodo({ name: formData.get("name") });
|
|
await addTodo(formData);
|
|
}
|
|
|
|
return (
|
|
<form action={formAction}>
|
|
{optimisticTodos.map(todo => (
|
|
<div key={todo.id} className={todo.sending ? "sending" : ""}>
|
|
{todo.name}
|
|
</div>
|
|
))}
|
|
</form>
|
|
);
|
|
}
|
|
```
|
|
|
|
#### `useFormStatus`
|
|
Provides form submission status:
|
|
```jsx
|
|
function SubmitButton() {
|
|
const { pending, data, method, action } = useFormStatus();
|
|
|
|
return (
|
|
<button type="submit" disabled={pending}>
|
|
{pending ? 'Submitting...' : 'Submit'}
|
|
</button>
|
|
);
|
|
}
|
|
```
|
|
|
|
#### `use`
|
|
Reads resources during rendering:
|
|
```jsx
|
|
function Profile({ userPromise }) {
|
|
const user = use(userPromise);
|
|
|
|
return <h1>{user.name}</h1>;
|
|
}
|
|
```
|
|
|
|
### 3. Improved Component Rendering
|
|
|
|
#### `ref` as a Prop
|
|
Function components can now receive `ref` as a regular prop:
|
|
```jsx
|
|
function MyInput({ placeholder, ref }) {
|
|
return <input placeholder={placeholder} ref={ref} />;
|
|
}
|
|
|
|
// Usage
|
|
<MyInput ref={inputRef} placeholder="Enter text" />
|
|
```
|
|
|
|
#### Direct Context Rendering
|
|
Context can be rendered directly without `.Provider`:
|
|
```jsx
|
|
// Before React 19
|
|
<ThemeContext.Provider value={theme}>
|
|
<App />
|
|
</ThemeContext.Provider>
|
|
|
|
// React 19
|
|
<ThemeContext value={theme}>
|
|
<App />
|
|
</ThemeContext>
|
|
```
|
|
|
|
#### Cleanup Functions for Refs
|
|
```jsx
|
|
function MyComponent() {
|
|
const ref = useCallback((node) => {
|
|
if (node) {
|
|
// Setup
|
|
node.focus();
|
|
|
|
// Cleanup function
|
|
return () => {
|
|
node.blur();
|
|
};
|
|
}
|
|
}, []);
|
|
|
|
return <input ref={ref} />;
|
|
}
|
|
```
|
|
|
|
#### Metadata Support
|
|
Components can render metadata tags directly:
|
|
```jsx
|
|
function BlogPost({ post }) {
|
|
return (
|
|
<article>
|
|
<title>{post.title}</title>
|
|
<meta name="description" content={post.excerpt} />
|
|
<h1>{post.title}</h1>
|
|
<p>{post.content}</p>
|
|
</article>
|
|
);
|
|
}
|
|
```
|
|
|
|
### 4. Performance Enhancements
|
|
|
|
#### Resource Preloading
|
|
```jsx
|
|
import { preload, preinit } from 'react-dom';
|
|
|
|
// Preload resources
|
|
preload('/api/user', { as: 'fetch' });
|
|
preinit('/styles.css', { as: 'style' });
|
|
```
|
|
|
|
#### Better Hydration Error Reporting
|
|
- More detailed error messages
|
|
- Better debugging information
|
|
- Improved compatibility with third-party scripts
|
|
|
|
### 5. Server Components
|
|
|
|
#### Server-Side Rendering
|
|
```jsx
|
|
// Server Component
|
|
async function BlogPost({ slug }) {
|
|
const post = await fetchPost(slug);
|
|
|
|
return (
|
|
<article>
|
|
<h1>{post.title}</h1>
|
|
<p>{post.content}</p>
|
|
</article>
|
|
);
|
|
}
|
|
```
|
|
|
|
#### Server Actions
|
|
```jsx
|
|
// actions.js
|
|
'use server'
|
|
|
|
export async function updateUser(formData) {
|
|
const name = formData.get('name');
|
|
// Update user on server
|
|
await database.updateUser({ name });
|
|
}
|
|
|
|
// Component
|
|
import { updateUser } from './actions.js';
|
|
|
|
function UserForm() {
|
|
return (
|
|
<form action={updateUser}>
|
|
<input name="name" />
|
|
<button type="submit">Update</button>
|
|
</form>
|
|
);
|
|
}
|
|
```
|
|
|
|
## Best Practices for Our Project
|
|
|
|
### 1. Forms and Data Management
|
|
- **Use Actions** for theme selection and configuration
|
|
- **Implement useOptimistic** for responsive theme preview
|
|
- **Leverage useFormStatus** for loading states
|
|
|
|
### 2. Component Design
|
|
- **Use ref as prop** for theme slot components
|
|
- **Implement cleanup functions** for theme CSS loading
|
|
- **Render metadata** for theme preview information
|
|
|
|
### 3. Performance
|
|
- **Preload theme assets** using new preloading APIs
|
|
- **Use Server Components** for theme discovery if server-side rendering is added
|
|
- **Implement error boundaries** with improved error handling
|
|
|
|
### 4. State Management
|
|
- **Use useActionState** for complex theme operations
|
|
- **Implement optimistic updates** for theme switching
|
|
- **Leverage new Context syntax** for theme providers
|
|
|
|
## Implementation Guidelines
|
|
|
|
### Theme Selection with Actions
|
|
```jsx
|
|
function ThemeBrowser({ themes }) {
|
|
const [selectedTheme, selectTheme] = useActionState(
|
|
async (currentState, formData) => {
|
|
const themeId = formData.get('themeId');
|
|
const theme = await loadTheme(themeId);
|
|
return theme;
|
|
},
|
|
null
|
|
);
|
|
|
|
return (
|
|
<form>
|
|
{themes.map(theme => (
|
|
<button
|
|
key={theme.id}
|
|
formAction={() => selectTheme(new FormData([['themeId', theme.id]]))}
|
|
>
|
|
{theme.name}
|
|
</button>
|
|
))}
|
|
</form>
|
|
);
|
|
}
|
|
```
|
|
|
|
### Optimistic Theme Switching
|
|
```jsx
|
|
function ThemePreview({ currentTheme, onThemeChange }) {
|
|
const [optimisticTheme, setOptimisticTheme] = useOptimistic(
|
|
currentTheme,
|
|
(state, newTheme) => newTheme
|
|
);
|
|
|
|
async function switchTheme(newTheme) {
|
|
setOptimisticTheme(newTheme);
|
|
await onThemeChange(newTheme);
|
|
}
|
|
|
|
return (
|
|
<div className={`theme-preview theme-${optimisticTheme.id}`}>
|
|
<h3>{optimisticTheme.name}</h3>
|
|
{/* Theme preview content */}
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
### Theme Context (New Syntax)
|
|
```jsx
|
|
function App() {
|
|
const [theme, setTheme] = useState(defaultTheme);
|
|
|
|
return (
|
|
<ThemeContext value={{ theme, setTheme }}>
|
|
<ThemeBrowser />
|
|
<SlideEditor />
|
|
</ThemeContext>
|
|
);
|
|
}
|
|
```
|
|
|
|
## Key Takeaways
|
|
|
|
1. **Embrace Actions** - Simplify form handling and state management
|
|
2. **Use Optimistic Updates** - Create responsive user interfaces
|
|
3. **Leverage New Hooks** - Reduce boilerplate code
|
|
4. **Improve Performance** - Utilize preloading and better error handling
|
|
5. **Simplify Context** - Use direct rendering without `.Provider`
|
|
6. **Handle Refs Better** - Pass refs as regular props to function components |