diff --git a/lib/README.md b/lib/README.md index 92696ca..11388e7 100644 --- a/lib/README.md +++ b/lib/README.md @@ -147,6 +147,36 @@ The `createAuth` function wraps your `AuthClient` implementation with an `Enhanc - `subscribe(() => { })`, subscribe to AuthClient state changes - `getSnapshot()`, returns the current state of the AuthClient +##### Reactive auth state with `useSyncExternalStore` + +`EnhancedAuthClient` is designed to work directly with React's [`useSyncExternalStore`](https://react.dev/reference/react/useSyncExternalStore) hook. This is the **recommended pattern for reading auth state inside components**, especially in multi-component layouts where auth changes must propagate correctly without relying on loading-state workarounds. + +The `subscribe` and `getSnapshot` methods are intentionally declared as bound arrow-function properties so they can be passed **directly** to `useSyncExternalStore` without wrapping: + +```tsx +import { useSyncExternalStore } from 'react'; +import { authClient } from './auth'; // the authClient returned by createAuth + +function MyComponent() { + const { isInitialized, isAuthenticated, tokens } = useSyncExternalStore( + authClient.subscribe, + authClient.getSnapshot, + ); + + if (!isInitialized) return ; + if (!isAuthenticated) return ; + + return ; +} +``` + +The snapshot returned by `getSnapshot()` contains: +- `isInitialized` — `true` once the client's `onInit` hook has completed +- `isAuthenticated` — `true` when the user is logged in and tokens are present +- `tokens` — the current tokens object returned by `login` or `refresh`; when no tokens are available (e.g. before login or after logout), this is an empty object + +Successful `login()`, `refresh()`, `logout()`, and initialization update the auth state and re-render all components that are subscribed via `useSyncExternalStore`. + --- ### Use multiple AuthClients