Add stores documentation with usage examples
This commit is contained in:
parent
184ecbbfcf
commit
01365d72bd
178
stores/README.md
Normal file
178
stores/README.md
Normal file
@ -0,0 +1,178 @@
|
||||
# WellNuo Stores
|
||||
|
||||
State management using Zustand for performant, scalable React state.
|
||||
|
||||
## Why Zustand?
|
||||
|
||||
Zustand provides several advantages over Context API:
|
||||
|
||||
1. **Better Performance** - Only components using specific values re-render
|
||||
2. **Simpler API** - No provider wrappers needed
|
||||
3. **TypeScript First** - Excellent type inference
|
||||
4. **Flexible** - Can be used outside React components
|
||||
5. **Smaller Bundle** - Lightweight library (~1KB)
|
||||
|
||||
## Available Stores
|
||||
|
||||
### Auth Store (`authStore.ts`)
|
||||
|
||||
Manages authentication state and user sessions.
|
||||
|
||||
**Features:**
|
||||
- OTP authentication flow (email → OTP → verify)
|
||||
- Automatic session checking on app start
|
||||
- Auto-logout on 401 unauthorized
|
||||
- User profile management
|
||||
- Optimized selector hooks
|
||||
|
||||
**Basic Usage:**
|
||||
|
||||
```tsx
|
||||
import { useAuthStore, initAuthStore } from '@/stores/authStore';
|
||||
|
||||
// 1. Initialize once at app start (in app/_layout.tsx)
|
||||
export default function RootLayout() {
|
||||
useEffect(() => {
|
||||
initAuthStore();
|
||||
}, []);
|
||||
}
|
||||
|
||||
// 2. Use in components
|
||||
function MyComponent() {
|
||||
const { user, isAuthenticated, logout } = useAuthStore();
|
||||
|
||||
return (
|
||||
<View>
|
||||
{isAuthenticated ? (
|
||||
<Text>Welcome {user?.firstName}</Text>
|
||||
) : (
|
||||
<Text>Please login</Text>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**Optimized Selectors:**
|
||||
|
||||
Use selector hooks when you only need specific values - prevents unnecessary re-renders:
|
||||
|
||||
```tsx
|
||||
import { useAuthUser, useIsAuthenticated } from '@/stores/authStore';
|
||||
|
||||
function UserProfile() {
|
||||
// Only re-renders when user changes
|
||||
const user = useAuthUser();
|
||||
|
||||
return <Text>{user?.email}</Text>;
|
||||
}
|
||||
|
||||
function LoginButton() {
|
||||
// Only re-renders when isAuthenticated changes
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
|
||||
return isAuthenticated ? <LogoutButton /> : <LoginButton />;
|
||||
}
|
||||
```
|
||||
|
||||
**Authentication Flow:**
|
||||
|
||||
```tsx
|
||||
function LoginScreen() {
|
||||
const { checkEmail, requestOtp, verifyOtp, error } = useAuthStore();
|
||||
|
||||
// Step 1: Check if email exists
|
||||
const emailResult = await checkEmail('user@example.com');
|
||||
|
||||
// Step 2: Request OTP code
|
||||
const otpResult = await requestOtp('user@example.com');
|
||||
|
||||
// Step 3: Verify OTP and authenticate
|
||||
const success = await verifyOtp('user@example.com', '123456');
|
||||
|
||||
if (success) {
|
||||
// User is now authenticated!
|
||||
// Navigate to dashboard
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**State Updates:**
|
||||
|
||||
```tsx
|
||||
function ProfileScreen() {
|
||||
const { updateUser } = useAuthStore();
|
||||
|
||||
// Update local state (doesn't call API)
|
||||
updateUser({ firstName: 'John', lastName: 'Doe' });
|
||||
|
||||
// To persist to server, also call:
|
||||
await api.updateProfile({ firstName: 'John', lastName: 'Doe' });
|
||||
}
|
||||
```
|
||||
|
||||
**Outside React:**
|
||||
|
||||
```tsx
|
||||
import { useAuthStore } from '@/stores/authStore';
|
||||
|
||||
// In utility functions or non-component code
|
||||
function isUserAuthenticated() {
|
||||
return useAuthStore.getState().isAuthenticated;
|
||||
}
|
||||
|
||||
// Trigger logout from anywhere
|
||||
function forceLogout() {
|
||||
useAuthStore.getState().logout();
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
All stores have comprehensive test coverage:
|
||||
|
||||
```bash
|
||||
# Run all store tests
|
||||
npm test -- stores/
|
||||
|
||||
# Run specific store tests
|
||||
npm test -- authStore.test.ts
|
||||
|
||||
# With coverage
|
||||
npm test -- --coverage stores/
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use Selectors** - Prefer `useAuthUser()` over `useAuthStore((state) => state.user)`
|
||||
2. **Initialize Once** - Call `initAuthStore()` only once at app startup
|
||||
3. **Granular Subscriptions** - Only subscribe to values you need
|
||||
4. **Type Safety** - Store is fully typed, use TypeScript benefits
|
||||
5. **Server Sync** - Remember to call API after updating store state
|
||||
|
||||
## Migration from Context
|
||||
|
||||
If migrating from AuthContext:
|
||||
|
||||
**Before (Context):**
|
||||
```tsx
|
||||
const { user, isAuthenticated } = useAuth();
|
||||
```
|
||||
|
||||
**After (Zustand):**
|
||||
```tsx
|
||||
const { user, isAuthenticated } = useAuthStore();
|
||||
```
|
||||
|
||||
The API is almost identical! Main difference: no Provider wrapper needed.
|
||||
|
||||
## Adding New Stores
|
||||
|
||||
Follow the pattern in `authStore.ts`:
|
||||
|
||||
1. Define state interface
|
||||
2. Define actions interface
|
||||
3. Create store with `create<State & Actions>()`
|
||||
4. Export store and selector hooks
|
||||
5. Add comprehensive tests
|
||||
6. Document in this README
|
||||
Loading…
x
Reference in New Issue
Block a user