mirror of https://github.com/usememos/memos
refactor(react-query): optimize config, add error boundary, and remove JSDoc
This commit combines multiple improvements to the React Query migration: Performance Optimization: - Increase default staleTime from 10s to 30s for better performance - Reduces unnecessary network requests while maintaining data freshness Error Handling: - Add ErrorBoundary component with user-friendly error UI - Integrated at app root level for comprehensive coverage - Provides error details and reload option Documentation: - Add docs/auth-architecture.md explaining AuthContext design decisions - Document why AuthContext is preferred over React Query for current user Code Cleanup: - Remove all JSDoc comments from hooks and components - Keep essential inline comments for clarity - Simplifies code readability Files modified: - src/lib/query-client.ts - Optimized staleTime - src/main.tsx - Added ErrorBoundary wrapper - src/components/ErrorBoundary.tsx - New component - src/hooks/useMemoQueries.ts - Removed JSDoc - src/hooks/useUserQueries.ts - Removed JSDoc - src/components/PagedMemoList/PagedMemoList.tsx - Removed JSDoc - docs/auth-architecture.md - New documentation All changes verified with TypeScript compilation and production build. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>pull/5405/head
parent
eed935ce44
commit
d4e08ae2bd
@ -0,0 +1,55 @@
|
||||
# Authentication State Architecture
|
||||
|
||||
## Current Approach: AuthContext
|
||||
|
||||
The application uses **AuthContext** for authentication state management, not React Query's `useCurrentUserQuery`. This is an intentional architectural decision.
|
||||
|
||||
### Why AuthContext Instead of React Query?
|
||||
|
||||
#### 1. **Synchronous Initialization**
|
||||
- AuthContext fetches user data during app initialization (`main.tsx`)
|
||||
- Provides synchronous access to `currentUser` throughout the app
|
||||
- No need to handle loading states in every component
|
||||
|
||||
#### 2. **Single Source of Truth**
|
||||
- User data fetched once on mount
|
||||
- All components get consistent, up-to-date user info
|
||||
- No race conditions from multiple query instances
|
||||
|
||||
#### 3. **Integration with React Query**
|
||||
- AuthContext pre-populates React Query cache after fetch (line 81-82 in `AuthContext.tsx`)
|
||||
- Best of both worlds: synchronous access + cache consistency
|
||||
- React Query hooks like `useNotifications()` can still use the cached user data
|
||||
|
||||
#### 4. **Simpler Component Code**
|
||||
```typescript
|
||||
// With AuthContext (current)
|
||||
const user = useCurrentUser(); // Always returns User | undefined
|
||||
|
||||
// With React Query (alternative)
|
||||
const { data: user, isLoading } = useCurrentUserQuery();
|
||||
if (isLoading) return <Spinner />;
|
||||
// Need loading handling everywhere
|
||||
```
|
||||
|
||||
### When to Use React Query for Auth?
|
||||
|
||||
Consider migrating auth to React Query if:
|
||||
- App needs real-time user profile updates from external sources
|
||||
- Multiple tabs need instant sync
|
||||
- User data changes frequently during a session
|
||||
|
||||
For Memos (a notes app where user profile rarely changes), AuthContext is the right choice.
|
||||
|
||||
### Future Considerations
|
||||
|
||||
The unused `useCurrentUserQuery()` hook in `useUserQueries.ts` is kept for potential future use. If requirements change (e.g., real-time collaboration on user profiles), migration path is clear:
|
||||
|
||||
1. Remove AuthContext
|
||||
2. Use `useCurrentUserQuery()` everywhere
|
||||
3. Handle loading states in components
|
||||
4. Add suspense boundaries if needed
|
||||
|
||||
## Recommendation
|
||||
|
||||
**Keep the current AuthContext approach.** It provides better DX and performance for this use case.
|
||||
@ -0,0 +1,70 @@
|
||||
import { AlertCircle, RefreshCw } from "lucide-react";
|
||||
import { Component, type ErrorInfo, type ReactNode } from "react";
|
||||
import { Button } from "./ui/button";
|
||||
|
||||
interface Props {
|
||||
children: ReactNode;
|
||||
fallback?: ReactNode;
|
||||
}
|
||||
|
||||
interface State {
|
||||
hasError: boolean;
|
||||
error: Error | null;
|
||||
}
|
||||
|
||||
export class ErrorBoundary extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = { hasError: false, error: null };
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(error: Error): State {
|
||||
return { hasError: true, error };
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
||||
console.error("ErrorBoundary caught an error:", error, errorInfo);
|
||||
}
|
||||
|
||||
handleReset = () => {
|
||||
this.setState({ hasError: false, error: null });
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
if (this.props.fallback) {
|
||||
return this.props.fallback;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-screen bg-background">
|
||||
<div className="max-w-md w-full p-6 space-y-4">
|
||||
<div className="flex items-center gap-3 text-destructive">
|
||||
<AlertCircle className="w-8 h-8" />
|
||||
<h1 className="text-2xl font-bold">Something went wrong</h1>
|
||||
</div>
|
||||
|
||||
<p className="text-foreground/70">
|
||||
An unexpected error occurred. This could be due to a network issue or a problem with the application.
|
||||
</p>
|
||||
|
||||
{this.state.error && (
|
||||
<details className="bg-muted p-3 rounded-md text-sm">
|
||||
<summary className="cursor-pointer font-medium mb-2">Error details</summary>
|
||||
<pre className="whitespace-pre-wrap break-words text-xs text-foreground/60">{this.state.error.message}</pre>
|
||||
</details>
|
||||
)}
|
||||
|
||||
<Button onClick={this.handleReset} className="w-full gap-2">
|
||||
<RefreshCw className="w-4 h-4" />
|
||||
Reload Application
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue