initial commit
This commit is contained in:
+50
@@ -0,0 +1,50 @@
|
||||
# React Runtime Crash Patterns
|
||||
|
||||
## Invalid Date → RangeError (white screen)
|
||||
|
||||
`new Date(undefined)` or `new Date(null)` creates an Invalid Date. Calling `.toLocaleDateString()` or `Intl.DateTimeFormat.format()` on it throws `RangeError: Invalid time value` — an uncaught runtime error that blanks the page.
|
||||
|
||||
**Fix:** Guard all date formatting functions:
|
||||
```typescript
|
||||
function formatDate(iso: string | undefined | null) {
|
||||
if (!iso) return '—';
|
||||
return new Intl.DateTimeFormat('en-US', { ... }).format(new Date(iso));
|
||||
}
|
||||
```
|
||||
|
||||
**Detection:** grep for `new Date(` calls in page components and verify each has a null/undefined guard.
|
||||
|
||||
## Nested component re-mount (input focus loss)
|
||||
|
||||
Defining a child component as a nested function inside a parent causes React to destroy/recreate it on every parent render. If the parent re-renders from a state update (e.g., zustand store change while typing), the input loses focus on every keystroke.
|
||||
|
||||
**Symptom:** Each character typed dismisses focus; user must click back into the field for the next character.
|
||||
|
||||
**Fix:** Extract to a file-level `memo` component:
|
||||
```typescript
|
||||
const ServiceRow = memo(function ServiceRow({ service, onUpdate, ... }: Props) {
|
||||
return <input value={service.price} onChange={e => onUpdate({ price: parseFloat(e.target.value) })} />
|
||||
});
|
||||
```
|
||||
|
||||
**Anti-pattern (causes focus loss):**
|
||||
```typescript
|
||||
function Parent() {
|
||||
const Child = ({ item }) => <input ... />; // New identity every render
|
||||
return items.map(i => <Child key={i.id} item={i} />);
|
||||
}
|
||||
```
|
||||
|
||||
## Blank screen with empty console
|
||||
|
||||
When a React lazy-loaded chunk has an import error, the page shows blank with zero console errors. The error is swallowed by the Suspense boundary. **Fix:** temporarily switch to eager imports in App.tsx to surface the error, then revert to lazy once fixed.
|
||||
|
||||
## tsc clean ≠ runtime clean
|
||||
|
||||
TypeScript compilation success does not catch:
|
||||
- JSON.parse on potentially-malformed strings
|
||||
- `new Date(undefined)` → RangeError
|
||||
- `.reduce()` / `.map()` on non-array values
|
||||
- Missing context providers (useToast without ToastProvider)
|
||||
|
||||
These all surface as blank pages or runtime crashes. After parallel fan-outs, smoke-test each page by navigating to its URL.
|
||||
Reference in New Issue
Block a user