feature/IO-3499-React-19: Documentation / Update node version on DockerFile
This commit is contained in:
468
_reference/REACT_19_FEATURES_GUIDE.md
Normal file
468
_reference/REACT_19_FEATURES_GUIDE.md
Normal file
@@ -0,0 +1,468 @@
|
||||
# React 19 Features Guide
|
||||
|
||||
## Overview
|
||||
This guide covers the new React 19 features available in our codebase and provides practical examples for implementing them.
|
||||
|
||||
---
|
||||
|
||||
## 1. New Hooks for Forms
|
||||
|
||||
### `useFormStatus` - Track Form Submission State
|
||||
|
||||
**What it does:** Provides access to the current form's submission status without manual state management.
|
||||
|
||||
**Use Case:** Show loading states on submit buttons, disable inputs during submission.
|
||||
|
||||
**Example:**
|
||||
```jsx
|
||||
import { useFormStatus } from 'react';
|
||||
|
||||
function SubmitButton() {
|
||||
const { pending } = useFormStatus();
|
||||
|
||||
return (
|
||||
<button type="submit" disabled={pending}>
|
||||
{pending ? 'Saving...' : 'Save'}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function JobForm({ onSave }) {
|
||||
return (
|
||||
<form action={onSave}>
|
||||
<input name="jobNumber" />
|
||||
<SubmitButton />
|
||||
</form>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- No manual `useState` for loading states
|
||||
- Automatic re-renders when form status changes
|
||||
- Better separation of concerns (button doesn't need form state)
|
||||
|
||||
---
|
||||
|
||||
### `useOptimistic` - Instant UI Updates
|
||||
|
||||
**What it does:** Updates UI immediately while async operations complete in the background.
|
||||
|
||||
**Use Case:** Comments, notes, status updates - anything where you want instant feedback.
|
||||
|
||||
**Example:**
|
||||
```jsx
|
||||
import { useState, useOptimistic } from 'react';
|
||||
|
||||
function JobNotes({ jobId, initialNotes }) {
|
||||
const [notes, setNotes] = useState(initialNotes);
|
||||
const [optimisticNotes, addOptimisticNote] = useOptimistic(
|
||||
notes,
|
||||
(current, newNote) => [...current, newNote]
|
||||
);
|
||||
|
||||
async function handleAddNote(formData) {
|
||||
const text = formData.get('note');
|
||||
const tempNote = { id: Date.now(), text, pending: true };
|
||||
|
||||
// Show immediately
|
||||
addOptimisticNote(tempNote);
|
||||
|
||||
// Save to server
|
||||
const saved = await saveNote(jobId, text);
|
||||
setNotes([...notes, saved]);
|
||||
}
|
||||
|
||||
return (
|
||||
<form action={handleAddNote}>
|
||||
<textarea name="note" />
|
||||
<button type="submit">Add Note</button>
|
||||
<ul>
|
||||
{optimisticNotes.map(note => (
|
||||
<li key={note.id} style={{ opacity: note.pending ? 0.5 : 1 }}>
|
||||
{note.text}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Perceived performance improvement
|
||||
- Better UX - users see changes instantly
|
||||
- Automatic rollback on error (if implemented)
|
||||
|
||||
---
|
||||
|
||||
### `useActionState` - Complete Form State Management
|
||||
|
||||
**What it does:** Manages async form submissions with built-in loading, error, and success states.
|
||||
|
||||
**Use Case:** Form validation, API submissions, complex form workflows.
|
||||
|
||||
**Example:**
|
||||
```jsx
|
||||
import { useActionState } from 'react';
|
||||
|
||||
async function createContract(prevState, formData) {
|
||||
const data = {
|
||||
customerId: formData.get('customerId'),
|
||||
vehicleId: formData.get('vehicleId'),
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await fetch('/api/contracts', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
return { error: 'Failed to create contract', data: null };
|
||||
}
|
||||
|
||||
return { error: null, data: await result.json() };
|
||||
} catch (err) {
|
||||
return { error: err.message, data: null };
|
||||
}
|
||||
}
|
||||
|
||||
function ContractForm() {
|
||||
const [state, submitAction, isPending] = useActionState(
|
||||
createContract,
|
||||
{ error: null, data: null }
|
||||
);
|
||||
|
||||
return (
|
||||
<form action={submitAction}>
|
||||
<input name="customerId" required />
|
||||
<input name="vehicleId" required />
|
||||
|
||||
<button type="submit" disabled={isPending}>
|
||||
{isPending ? 'Creating...' : 'Create Contract'}
|
||||
</button>
|
||||
|
||||
{state.error && <div className="error">{state.error}</div>}
|
||||
{state.data && <div className="success">Contract #{state.data.id} created!</div>}
|
||||
</form>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Replaces multiple `useState` calls
|
||||
- Built-in pending state
|
||||
- Cleaner error handling
|
||||
- Type-safe with TypeScript
|
||||
|
||||
---
|
||||
|
||||
## 2. Actions API
|
||||
|
||||
The Actions API simplifies form submissions and async operations by using the native `action` prop on forms.
|
||||
|
||||
### Traditional Approach (React 18):
|
||||
```jsx
|
||||
function OldForm() {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
async function handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const formData = new FormData(e.target);
|
||||
await saveData(formData);
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
{/* form fields */}
|
||||
</form>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Modern Approach (React 19):
|
||||
```jsx
|
||||
import { useActionState } from 'react';
|
||||
|
||||
function NewForm() {
|
||||
const [state, formAction, isPending] = useActionState(async (_, formData) => {
|
||||
return await saveData(formData);
|
||||
}, null);
|
||||
|
||||
return (
|
||||
<form action={formAction}>
|
||||
{/* form fields */}
|
||||
</form>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Practical Implementation Examples
|
||||
|
||||
### Example 1: Owner/Customer Form with Optimistic UI
|
||||
|
||||
```jsx
|
||||
import { useOptimistic, useActionState } from 'react';
|
||||
import { Form, Input, Button } from 'antd';
|
||||
|
||||
function OwnerFormModern({ owner, onSave }) {
|
||||
const [optimisticOwner, setOptimisticOwner] = useOptimistic(
|
||||
owner,
|
||||
(current, updates) => ({ ...current, ...updates })
|
||||
);
|
||||
|
||||
const [state, submitAction, isPending] = useActionState(
|
||||
async (_, formData) => {
|
||||
const updates = {
|
||||
name: formData.get('name'),
|
||||
phone: formData.get('phone'),
|
||||
email: formData.get('email'),
|
||||
};
|
||||
|
||||
// Show changes immediately
|
||||
setOptimisticOwner(updates);
|
||||
|
||||
// Save to server
|
||||
try {
|
||||
await onSave(updates);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
},
|
||||
{ success: null }
|
||||
);
|
||||
|
||||
return (
|
||||
<form action={submitAction}>
|
||||
<Form.Item label="Name">
|
||||
<Input name="name" defaultValue={optimisticOwner.name} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Phone">
|
||||
<Input name="phone" defaultValue={optimisticOwner.phone} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Email">
|
||||
<Input name="email" defaultValue={optimisticOwner.email} />
|
||||
</Form.Item>
|
||||
|
||||
<Button type="primary" htmlType="submit" loading={isPending}>
|
||||
{isPending ? 'Saving...' : 'Save Owner'}
|
||||
</Button>
|
||||
|
||||
{state.error && <div className="error">{state.error}</div>}
|
||||
</form>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2: Job Status Update with useFormStatus
|
||||
|
||||
```jsx
|
||||
import { useFormStatus } from 'react';
|
||||
|
||||
function JobStatusButton({ status }) {
|
||||
const { pending } = useFormStatus();
|
||||
|
||||
return (
|
||||
<button disabled={pending}>
|
||||
{pending ? 'Updating...' : `Mark as ${status}`}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function JobStatusForm({ jobId, currentStatus }) {
|
||||
async function updateStatus(formData) {
|
||||
const newStatus = formData.get('status');
|
||||
await fetch(`/api/jobs/${jobId}/status`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify({ status: newStatus }),
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<form action={updateStatus}>
|
||||
<input type="hidden" name="status" value="IN_PROGRESS" />
|
||||
<JobStatusButton status="In Progress" />
|
||||
</form>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Third-Party Library Compatibility
|
||||
|
||||
### ✅ Fully Compatible (Already in use)
|
||||
|
||||
1. **Ant Design 6.2.0**
|
||||
- ✅ Full React 19 support out of the box
|
||||
- ✅ No patches or workarounds needed
|
||||
- 📝 Note: Ant Design 6 was built with React 19 in mind
|
||||
|
||||
2. **React-Redux 9.2.0**
|
||||
- ✅ Full React 19 support
|
||||
- ✅ All hooks (`useSelector`, `useDispatch`) work correctly
|
||||
- 📝 Tip: Continue using hooks over `connect()` HOC
|
||||
|
||||
3. **Apollo Client 4.0.13**
|
||||
- ✅ Compatible with React 19
|
||||
- ✅ `useQuery`, `useMutation` work correctly
|
||||
- 📝 Note: Supports React 19's concurrent features
|
||||
|
||||
4. **React Router 7.12.0**
|
||||
- ✅ Full React 19 support
|
||||
- ✅ All navigation hooks compatible
|
||||
- ✅ Future flags enabled for optimal performance
|
||||
|
||||
### Integration Notes
|
||||
|
||||
All our major dependencies are already compatible with React 19:
|
||||
- No additional patches needed
|
||||
- No breaking changes in current code
|
||||
- All hooks and patterns continue to work
|
||||
|
||||
---
|
||||
|
||||
## 5. Migration Strategy
|
||||
|
||||
### Gradual Adoption Approach
|
||||
|
||||
**Phase 1: Learn** (Current)
|
||||
- Review this guide
|
||||
- Understand new hooks and patterns
|
||||
- Identify good candidates for migration
|
||||
|
||||
**Phase 2: Pilot** (Recommended)
|
||||
- Start with new features/forms
|
||||
- Try `useActionState` in one new form
|
||||
- Measure developer experience improvement
|
||||
|
||||
**Phase 3: Refactor** (Optional)
|
||||
- Gradually update high-traffic forms
|
||||
- Add optimistic UI to user-facing features
|
||||
- Simplify complex form state management
|
||||
|
||||
### Good Candidates for React 19 Features
|
||||
|
||||
1. **Forms with Complex Loading States**
|
||||
- Contract creation
|
||||
- Job creation/editing
|
||||
- Owner/Vehicle forms
|
||||
- → Use `useActionState`
|
||||
|
||||
2. **Instant Feedback Features**
|
||||
- Adding job notes
|
||||
- Status updates
|
||||
- Comments/messages
|
||||
- → Use `useOptimistic`
|
||||
|
||||
3. **Submit Buttons**
|
||||
- Any form button that needs loading state
|
||||
- → Use `useFormStatus`
|
||||
|
||||
### Don't Rush to Refactor
|
||||
|
||||
**Keep using current patterns for:**
|
||||
- Ant Design Form components (already excellent)
|
||||
- Redux for global state
|
||||
- Apollo Client for GraphQL
|
||||
- Existing working code
|
||||
|
||||
**Only refactor when:**
|
||||
- Building new features
|
||||
- Fixing bugs in forms
|
||||
- Simplifying overly complex state management
|
||||
|
||||
---
|
||||
|
||||
## 6. Performance Improvements in React 19
|
||||
|
||||
### Automatic Optimizations
|
||||
|
||||
React 19 includes built-in compiler optimizations that automatically improve performance:
|
||||
|
||||
1. **Automatic Memoization**
|
||||
- Less need for `useMemo` and `useCallback`
|
||||
- Components automatically optimize re-renders
|
||||
|
||||
2. **Improved Concurrent Rendering**
|
||||
- Better handling of heavy operations
|
||||
- Smoother UI during data loading
|
||||
|
||||
3. **Enhanced Suspense**
|
||||
- Better loading states
|
||||
- Improved streaming SSR
|
||||
|
||||
**What this means for us:**
|
||||
- Existing code may run faster without changes
|
||||
- Future code will be easier to write
|
||||
- Less manual optimization needed
|
||||
|
||||
---
|
||||
|
||||
## 7. Resources
|
||||
|
||||
### Official Documentation
|
||||
- [React 19 Release Notes](https://react.dev/blog/2024/12/05/react-19)
|
||||
- [useActionState](https://react.dev/reference/react/useActionState)
|
||||
- [useFormStatus](https://react.dev/reference/react-dom/hooks/useFormStatus)
|
||||
- [useOptimistic](https://react.dev/reference/react/useOptimistic)
|
||||
|
||||
### Migration Guides
|
||||
- [React 18 to 19 Upgrade Guide](https://react.dev/blog/2024/04/25/react-19-upgrade-guide)
|
||||
- [Actions API Documentation](https://react.dev/reference/react/useActionState)
|
||||
|
||||
### Community Resources
|
||||
- [React 19 Features Tutorial](https://www.freecodecamp.org/news/react-19-actions-simpliy-form-submission-and-loading-states/)
|
||||
- [Practical Examples](https://blog.logrocket.com/react-useactionstate/)
|
||||
|
||||
---
|
||||
|
||||
## 8. Summary
|
||||
|
||||
### Current Status
|
||||
✅ **All dependencies compatible with React 19**
|
||||
- Ant Design 6.2.0 ✓
|
||||
- React-Redux 9.2.0 ✓
|
||||
- Apollo Client 4.0.13 ✓
|
||||
- React Router 7.12.0 ✓
|
||||
|
||||
### New Features Available
|
||||
🎯 **Ready to use in new code:**
|
||||
- `useFormStatus` - Track form submission state
|
||||
- `useOptimistic` - Instant UI updates
|
||||
- `useActionState` - Complete form state management
|
||||
- Actions API - Cleaner form handling
|
||||
|
||||
### Recommendations
|
||||
1. ✅ **No immediate action required** - Everything works
|
||||
2. 🎯 **Start using new features in new code** - Especially forms
|
||||
3. 📚 **Learn gradually** - No need to refactor everything
|
||||
4. 🚀 **Enjoy performance improvements** - Automatic optimizations active
|
||||
|
||||
---
|
||||
|
||||
## Questions or Need Help?
|
||||
|
||||
Feel free to:
|
||||
- Try examples in a branch first
|
||||
- Ask the team for code reviews
|
||||
- Share patterns that work well
|
||||
- Document new patterns you discover
|
||||
|
||||
**Happy coding with React 19! 🎉**
|
||||
Reference in New Issue
Block a user