Global State & Context
Overview
Blogify manages authentication and current user data through a centralized User Context. This context ensures that the user's session is synchronized across all components, handling the transition between logged-out and logged-in states automatically by listening to Supabase authentication events.
The state is exposed via the useUser hook, which allows any component in the application to access the current session without manual prop drilling.
The useUser Hook
The useUser hook is the primary interface for interacting with the global authentication state.
import { useUser } from '@/context/UserContext';
const MyComponent = () => {
const { user, loading } = useUser();
if (loading) return <Spinner />;
return (
<div>
{user ? `Welcome back, ${user.name}` : "Please log in"}
</div>
);
};
Context Properties
| Property | Type | Description |
| :--- | :--- | :--- |
| user | User \| null | The current authenticated user object. Returns null if the user is not logged in. |
| loading | boolean | Indicates if the initial session check or a state transition is in progress. |
User State Interface
The user object returned by the context follows the standard User interface defined in the API layer:
interface User {
id: string;
name: string;
email: string;
profile_picture_url?: string;
created_at: string;
}
Authentication Lifecycle
The global state is updated automatically in the following scenarios:
- Initial Load: On application mount, the provider checks
localStoragevia the Supabase client to restore an existing session. - Sign In/Sign Up: When a user logs in (e.g., in the
LoginPage), the Supabase client triggers an internal state change event which theUserContextcaptures to update the globaluserobject. - Profile Updates: When a user modifies their profile, the updated data is typically reflected in the context to ensure the UI (like Navbars or Dashboards) stays current.
- Sign Out: Clearing the session via the Supabase client resets the
userstate tonull.
Protecting Routes and Actions
The application uses the global state to handle access control through two primary patterns:
1. The RequireAuth Component
Wrapped around protected pages or components to prevent access by unauthenticated users.
// frontend/src/app/posts/new/page.tsx
import { RequireAuth } from '@/components';
export default function NewPostPage() {
return (
<RequireAuth>
<NewPostContent />
</RequireAuth>
);
}
2. Manual State Checks
Used for conditional rendering of UI elements based on ownership or login status.
const { user } = useUser();
// Only show edit button if the current user owns the post
{user?.id === post.user_id && (
<EditPostButton postId={post.id} />
)}
Best Practices
- Check
loadingfirst: Always verify thatloadingisfalsebefore redirecting users to login pages, otherwise, users may be redirected during the brief moment the app is restoring their session. - Client-Side Only: Since
UserContextrelies on browser APIs (likelocalStoragefor session persistence), it is strictly a Client Component feature. Ensure any component consuminguseUserincludes the"use client"directive.