@mr.dj2u/knowledge 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/content/checklists/push-merge-loop.md +17 -17
  2. package/dist/content/checklists/unified-agent-bundle-validation.md +9 -9
  3. package/dist/content/examples/push-merge-loop.md +14 -14
  4. package/dist/content/examples/unified-agent-bundle-bootstrap.md +8 -8
  5. package/dist/content/guides/animation-performance.md +31 -1
  6. package/dist/content/guides/post-create-onboarding.md +140 -140
  7. package/dist/content/patterns/animation/animation-motion-selection.md +155 -0
  8. package/dist/content/patterns/api/api-routes.md +313 -313
  9. package/dist/content/patterns/api/error-handling.md +310 -310
  10. package/dist/content/patterns/database/drizzle-schema.md +279 -279
  11. package/dist/content/patterns/database/migrations.md +364 -364
  12. package/dist/content/patterns/database/query-organization.md +536 -536
  13. package/dist/content/patterns/database/relations.md +449 -449
  14. package/dist/content/patterns/deployment/build-configuration.md +440 -440
  15. package/dist/content/patterns/deployment/ci-cd-patterns.md +447 -447
  16. package/dist/content/patterns/deployment/environment-config.md +379 -379
  17. package/dist/content/patterns/deployment/hosting-setup.md +424 -424
  18. package/dist/content/patterns/project/configuration-patterns.md +459 -459
  19. package/dist/content/patterns/project/documentation-org.md +506 -506
  20. package/dist/content/patterns/project/folder-structure.md +397 -397
  21. package/dist/content/patterns/project/library-exports.md +464 -464
  22. package/dist/content/patterns/project/monorepo-structure.md +500 -500
  23. package/dist/content/patterns/routing/dynamic-routes.md +220 -220
  24. package/dist/content/patterns/routing/file-based-routing.md +185 -185
  25. package/dist/content/patterns/routing/route-groups.md +428 -428
  26. package/dist/content/patterns/state/persistence-middleware.md +520 -520
  27. package/dist/content/patterns/state/selector-hooks.md +537 -537
  28. package/dist/content/patterns/state/store-organization.md +538 -538
  29. package/dist/content/patterns/state/zustand-patterns.md +347 -347
  30. package/dist/content/patterns/styling/component-styling.md +467 -467
  31. package/dist/content/patterns/styling/responsive-patterns.md +397 -397
  32. package/dist/content/patterns/styling/theme-configuration.md +425 -425
  33. package/dist/content/patterns/styling/uniwind-setup.md +411 -411
  34. package/dist/content/prompts/continue-development.md +35 -35
  35. package/dist/content/prompts/fix-seo.md +29 -29
  36. package/dist/content/prompts/onboard-new-expo-app.md +11 -11
  37. package/dist/content/prompts/prepare-deploy.md +29 -29
  38. package/dist/content/prompts/project-research-plan.md +29 -29
  39. package/dist/content/prompts/push-merge-loop.md +25 -25
  40. package/dist/content/prompts/review-expo-project.md +29 -29
  41. package/dist/content/prompts/review-motion.md +58 -0
  42. package/dist/content/prompts/run-doctor.md +38 -38
  43. package/dist/content/prompts/wrap-up.md +67 -67
  44. package/dist/content/reference/create-expo-stack-uniwind.md +29 -29
  45. package/dist/content/reference/mcp-sdk-transport.md +30 -30
  46. package/dist/content/reference/reference-repo-evacuation.md +31 -31
  47. package/dist/content/resource-index.json +3 -0
  48. package/dist/content/skills/animation-motion.md +68 -0
  49. package/dist/content/skills/api-routes.md +33 -33
  50. package/dist/content/skills/continue-development.md +32 -32
  51. package/dist/content/skills/debugging.md +32 -32
  52. package/dist/content/skills/deployment.md +32 -32
  53. package/dist/content/skills/dev-server-management.md +32 -32
  54. package/dist/content/skills/env-vars.md +32 -32
  55. package/dist/content/skills/expo-router-architecture.md +33 -33
  56. package/dist/content/skills/expo-ssr-safety.md +32 -32
  57. package/dist/content/skills/plugin-creation.md +41 -41
  58. package/dist/content/skills/production-server-patterns.md +31 -31
  59. package/dist/content/skills/project-onboarding.md +31 -31
  60. package/dist/content/skills/research-plan-intake.md +32 -32
  61. package/dist/content/skills/seo-metadata.md +31 -31
  62. package/dist/content/skills/super-stack-startup.md +34 -34
  63. package/dist/content/skills/uniwind-theming.md +32 -32
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +27 -1
  66. package/dist/index.js.map +1 -1
  67. package/dist/patterns/index.d.ts +9 -1
  68. package/dist/patterns/index.d.ts.map +1 -1
  69. package/dist/patterns/index.js +17 -0
  70. package/dist/patterns/index.js.map +1 -1
  71. package/dist/prompts/index.d.ts.map +1 -1
  72. package/dist/prompts/index.js +17 -0
  73. package/dist/prompts/index.js.map +1 -1
  74. package/package.json +6 -1
@@ -1,348 +1,348 @@
1
- # Zustand State Management
2
-
3
- ## Description
4
-
5
- Zustand provides lightweight atomic state management with TypeScript type inference, optional persistence middleware, and selector hooks for optimal re-renders. Stores are created without providers, maintaining flat structure with computed properties derived from state, and AsyncStorage/localStorage integration for cross-platform persistence.
6
-
7
- ## When to Use
8
-
9
- **Use Zustand** for:
10
- - ✅ Global application state (auth, user, settings)
11
- - ✅ Feature-level state with persistence needs
12
- - ✅ State requiring type-safe selectors
13
- - ✅ Atomic updates without action dispatchers
14
-
15
- ## Code Example
16
-
17
- ### Basic Store with Persistence
18
-
19
- ```typescript
20
- // File: src/store/authStore.ts
21
- import { create } from 'zustand';
22
- import { persist, createJSONStorage } from 'zustand/middleware';
23
- import AsyncStorage from '@react-native-async-storage/async-storage';
24
-
25
- export interface AuthState {
26
- // State
27
- user: User | null;
28
- profile: Profile | null;
29
- session: Session | null;
30
- isLoggedIn: boolean;
31
- loading: boolean;
32
-
33
- // Computed properties (derived state)
34
- get isAdult(): boolean;
35
- get canUseSocialFeatures(): boolean;
36
- get isVip(): boolean;
37
-
38
- // Actions
39
- setUser: (user: User | null) => void;
40
- setProfile: (profile: Profile | null) => void;
41
- signOut: () => Promise<void>;
42
- initializeAuth: () => Promise<void>;
43
- }
44
-
45
- export const useAuthStore = create<AuthState>()(
46
- persist(
47
- (set, get) => ({
48
- // Initial state
49
- user: null,
50
- profile: null,
51
- session: null,
52
- isLoggedIn: false,
53
- loading: true,
54
-
55
- // Computed properties
56
- get isAdult(): boolean {
57
- const profile = get().profile;
58
- if (!profile?.dateOfBirth) return false;
59
- const age = calculateAge(profile.dateOfBirth);
60
- return age >= 18;
61
- },
62
-
63
- get canUseSocialFeatures(): boolean {
64
- return get().isLoggedIn && get().isAdult;
65
- },
66
-
67
- get isVip(): boolean {
68
- return get().profile?.vipStatus === true;
69
- },
70
-
71
- // Actions
72
- setUser: (user) => set({ user, isLoggedIn: !!user }),
73
-
74
- setProfile: (profile) => set({ profile }),
75
-
76
- signOut: async () => {
77
- await supabase.auth.signOut();
78
- set({
79
- user: null,
80
- profile: null,
81
- session: null,
82
- isLoggedIn: false,
83
- });
84
- },
85
-
86
- initializeAuth: async () => {
87
- set({ loading: true });
88
- try {
89
- const { data } = await supabase.auth.getSession();
90
- if (data.session?.user) {
91
- const profile = await fetchProfile(data.session.user.id);
92
- set({
93
- user: data.session.user,
94
- profile,
95
- session: data.session,
96
- isLoggedIn: true,
97
- loading: false,
98
- });
99
- } else {
100
- set({ loading: false });
101
- }
102
- } catch (error) {
103
- console.error('Auth init error:', error);
104
- set({ loading: false });
105
- }
106
- },
107
- }),
108
- {
109
- name: 'auth-storage',
110
- storage: createJSONStorage(() => AsyncStorage),
111
- // Only persist specific fields
112
- partialize: (state) => ({
113
- user: state.user,
114
- profile: state.profile,
115
- session: state.session,
116
- }),
117
- }
118
- )
119
- );
120
- ```
121
-
122
- **From:** PokePages/src/store/authStore.ts, core-monorepo pattern
123
-
124
- ### Selector Hooks for Performance
125
-
126
- ```typescript
127
- // ✅ GOOD - Custom selector hooks prevent unnecessary re-renders
128
-
129
- // Only re-renders when user email changes
130
- export const useUserEmail = () =>
131
- useAuthStore((state) => state.user?.email);
132
-
133
- // Only re-renders when isAdult computed property changes
134
- export const useIsAdult = () =>
135
- useAuthStore((state) => state.isAdult);
136
-
137
- // Multi-selector in single hook
138
- export const useUserWithProfile = () =>
139
- useAuthStore((state) => ({
140
- user: state.user,
141
- profile: state.profile,
142
- isLoggedIn: state.isLoggedIn,
143
- }));
144
-
145
- // Usage in component
146
- function UserCard() {
147
- const email = useUserEmail();
148
- const { profile } = useUserWithProfile();
149
-
150
- // Only re-renders when email or profile object reference changes
151
- return <Text>{email}</Text>;
152
- }
153
- ```
154
-
155
- ### Store for Favorites with Toggle
156
-
157
- ```typescript
158
- // File: src/store/favoriteFeaturesStore.ts
159
- import { create } from 'zustand';
160
- import { persist, createJSONStorage } from 'zustand/middleware';
161
- import AsyncStorage from '@react-native-async-storage/async-storage';
162
-
163
- export interface FavoritesState {
164
- favorites: Record<string, boolean>;
165
- toggleFavorite: (key: string) => void;
166
- isFavorite: (key: string) => boolean;
167
- }
168
-
169
- export const useFavoritesStore = create<FavoritesState>()(
170
- persist(
171
- (set, get) => ({
172
- favorites: {},
173
-
174
- toggleFavorite: (key) =>
175
- set((state) => ({
176
- favorites: {
177
- ...state.favorites,
178
- [key]: !state.favorites[key],
179
- },
180
- })),
181
-
182
- isFavorite: (key) => !!get().favorites[key],
183
- }),
184
- {
185
- name: 'favorites-storage',
186
- storage: createJSONStorage(() => AsyncStorage),
187
- }
188
- )
189
- );
190
-
191
- // Selector hooks
192
- export const useIsFavorite = (key: string) =>
193
- useFavoritesStore((state) => state.isFavorite(key));
194
-
195
- export const useToggleFavorite = () =>
196
- useFavoritesStore((state) => state.toggleFavorite);
197
-
198
- // Component usage
199
- function FavoriteButton({ pageKey }: { pageKey: string }) {
200
- const isFavorite = useIsFavorite(pageKey);
201
- const toggle = useToggleFavorite();
202
-
203
- return (
204
- <Pressable onPress={() => toggle(pageKey)}>
205
- <Text>{isFavorite ? '⭐' : '☆'}</Text>
206
- </Pressable>
207
- );
208
- }
209
- ```
210
-
211
- **From:** PokePages/src/store/favoriteFeaturesStore.ts
212
-
213
- ## Configuration
214
-
215
- ### Cross-Platform Storage Setup
216
-
217
- ```typescript
218
- // File: src/utils/createCrossPlatformStorage.ts
219
- import { Platform } from 'react-native';
220
- import AsyncStorage from '@react-native-async-storage/async-storage';
221
- import { createJSONStorage } from 'zustand/middleware';
222
-
223
- export function createCrossPlatformStorage() {
224
- if (Platform.OS === 'web') {
225
- return createJSONStorage(() => ({
226
- getItem: (key) => localStorage.getItem(key),
227
- setItem: (key, value) => localStorage.setItem(key, value),
228
- removeItem: (key) => localStorage.removeItem(key),
229
- }));
230
- }
231
-
232
- return createJSONStorage(() => AsyncStorage);
233
- }
234
-
235
- // Use in stores
236
- export const useStore = create<State>()(
237
- persist(
238
- (set) => ({ /* state */ }),
239
- {
240
- storage: createCrossPlatformStorage(),
241
- }
242
- )
243
- );
244
- ```
245
-
246
- ## Best Practices
247
-
248
- ### ✅ DO
249
-
250
- 1. **Use selector hooks** to prevent unnecessary re-renders
251
- ```typescript
252
- // ✅ GOOD - only subscribes to email
253
- const email = useAuthStore((state) => state.user?.email);
254
-
255
- // ❌ BAD - subscribes to entire store
256
- const { user, profile, session, ... } = useAuthStore();
257
- ```
258
-
259
- 2. **Keep stores flat** — avoid nested objects
260
- ```typescript
261
- // ✅ GOOD - flat structure
262
- userId: '123'
263
- userName: 'alice'
264
- userEmail: 'alice@example.com'
265
-
266
- // ❌ BAD - nested (causes unnecessary re-renders)
267
- user: { id: '123', name: 'alice', email: '...' }
268
- ```
269
-
270
- 3. **Use computed properties (getters)** for derived state
271
- ```typescript
272
- get isAdult(): boolean {
273
- return calculateAge(get().profile?.dateOfBirth) >= 18;
274
- }
275
- ```
276
-
277
- 4. **Partial persistence** — only persist necessary fields
278
- ```typescript
279
- partialize: (state) => ({
280
- user: state.user,
281
- theme: state.theme,
282
- // Don't persist: loading, errors, temporary UI state
283
- })
284
- ```
285
-
286
- 5. **Split stores** by domain/feature
287
- ```typescript
288
- useAuthStore() // auth + user
289
- useThemeStore() // app theme
290
- useFavoritesStore() // favorites
291
- ```
292
-
293
- ### ❌ DON'T
294
-
295
- 1. **Don't use context** for everything
296
- ```typescript
297
- // ❌ AVOID - causes re-renders of all consumers
298
- <UserContext.Provider value={{ user, setUser, ... }}>
299
-
300
- // ✅ USE - only subscribed components re-render
301
- const user = useUserStore((state) => state.user);
302
- ```
303
-
304
- 2. **Don't persist state that changes frequently**
305
- ```typescript
306
- // ❌ BAD - persists on every keystroke
307
- persist((set) => ({
308
- searchQuery: '',
309
- setSearchQuery: (q) => set({ searchQuery: q })
310
- }))
311
-
312
- // ✅ GOOD - only persist final state
313
- onChangeText={(q) => dispatch(setSearchQuery(q))} // local only
314
- ```
315
-
316
- 3. **Don't store derived data** that can be computed
317
- ```typescript
318
- // ❌ BAD - will get out of sync
319
- user: { id: '1', name: 'alice', email: 'alice@ex.com' }
320
- userDisplayName: 'alice' // Duplicate!
321
-
322
- // ✅ GOOD - compute on demand
323
- get userDisplayName() {
324
- return get().user?.name;
325
- }
326
- ```
327
-
328
- 4. **Don't forget to handle undefined** from selectors
329
- ```typescript
330
- // ❌ RISKY
331
- const email = useAuthStore((state) => state.user?.email);
332
- return <Text>{email}</Text>; // Could be undefined
333
-
334
- // ✅ SAFE
335
- const email = useAuthStore((state) => state.user?.email);
336
- return <Text>{email || 'No email'}</Text>;
337
- ```
338
-
339
- ## Related Patterns
340
-
341
- - [Store Organization](./store-organization.md) — Multi-store patterns
342
- - [Persistence Middleware](./persistence-middleware.md) — AsyncStorage integration
343
- - [Selector Hooks](./selector-hooks.md) — Performance optimization
344
-
345
- ---
346
-
347
- *Pattern extracted from production repositories: PokePages, core-monorepo, time2pay*
1
+ # Zustand State Management
2
+
3
+ ## Description
4
+
5
+ Zustand provides lightweight atomic state management with TypeScript type inference, optional persistence middleware, and selector hooks for optimal re-renders. Stores are created without providers, maintaining flat structure with computed properties derived from state, and AsyncStorage/localStorage integration for cross-platform persistence.
6
+
7
+ ## When to Use
8
+
9
+ **Use Zustand** for:
10
+ - ✅ Global application state (auth, user, settings)
11
+ - ✅ Feature-level state with persistence needs
12
+ - ✅ State requiring type-safe selectors
13
+ - ✅ Atomic updates without action dispatchers
14
+
15
+ ## Code Example
16
+
17
+ ### Basic Store with Persistence
18
+
19
+ ```typescript
20
+ // File: src/store/authStore.ts
21
+ import { create } from 'zustand';
22
+ import { persist, createJSONStorage } from 'zustand/middleware';
23
+ import AsyncStorage from '@react-native-async-storage/async-storage';
24
+
25
+ export interface AuthState {
26
+ // State
27
+ user: User | null;
28
+ profile: Profile | null;
29
+ session: Session | null;
30
+ isLoggedIn: boolean;
31
+ loading: boolean;
32
+
33
+ // Computed properties (derived state)
34
+ get isAdult(): boolean;
35
+ get canUseSocialFeatures(): boolean;
36
+ get isVip(): boolean;
37
+
38
+ // Actions
39
+ setUser: (user: User | null) => void;
40
+ setProfile: (profile: Profile | null) => void;
41
+ signOut: () => Promise<void>;
42
+ initializeAuth: () => Promise<void>;
43
+ }
44
+
45
+ export const useAuthStore = create<AuthState>()(
46
+ persist(
47
+ (set, get) => ({
48
+ // Initial state
49
+ user: null,
50
+ profile: null,
51
+ session: null,
52
+ isLoggedIn: false,
53
+ loading: true,
54
+
55
+ // Computed properties
56
+ get isAdult(): boolean {
57
+ const profile = get().profile;
58
+ if (!profile?.dateOfBirth) return false;
59
+ const age = calculateAge(profile.dateOfBirth);
60
+ return age >= 18;
61
+ },
62
+
63
+ get canUseSocialFeatures(): boolean {
64
+ return get().isLoggedIn && get().isAdult;
65
+ },
66
+
67
+ get isVip(): boolean {
68
+ return get().profile?.vipStatus === true;
69
+ },
70
+
71
+ // Actions
72
+ setUser: (user) => set({ user, isLoggedIn: !!user }),
73
+
74
+ setProfile: (profile) => set({ profile }),
75
+
76
+ signOut: async () => {
77
+ await supabase.auth.signOut();
78
+ set({
79
+ user: null,
80
+ profile: null,
81
+ session: null,
82
+ isLoggedIn: false,
83
+ });
84
+ },
85
+
86
+ initializeAuth: async () => {
87
+ set({ loading: true });
88
+ try {
89
+ const { data } = await supabase.auth.getSession();
90
+ if (data.session?.user) {
91
+ const profile = await fetchProfile(data.session.user.id);
92
+ set({
93
+ user: data.session.user,
94
+ profile,
95
+ session: data.session,
96
+ isLoggedIn: true,
97
+ loading: false,
98
+ });
99
+ } else {
100
+ set({ loading: false });
101
+ }
102
+ } catch (error) {
103
+ console.error('Auth init error:', error);
104
+ set({ loading: false });
105
+ }
106
+ },
107
+ }),
108
+ {
109
+ name: 'auth-storage',
110
+ storage: createJSONStorage(() => AsyncStorage),
111
+ // Only persist specific fields
112
+ partialize: (state) => ({
113
+ user: state.user,
114
+ profile: state.profile,
115
+ session: state.session,
116
+ }),
117
+ }
118
+ )
119
+ );
120
+ ```
121
+
122
+ **From:** PokePages/src/store/authStore.ts, core-monorepo pattern
123
+
124
+ ### Selector Hooks for Performance
125
+
126
+ ```typescript
127
+ // ✅ GOOD - Custom selector hooks prevent unnecessary re-renders
128
+
129
+ // Only re-renders when user email changes
130
+ export const useUserEmail = () =>
131
+ useAuthStore((state) => state.user?.email);
132
+
133
+ // Only re-renders when isAdult computed property changes
134
+ export const useIsAdult = () =>
135
+ useAuthStore((state) => state.isAdult);
136
+
137
+ // Multi-selector in single hook
138
+ export const useUserWithProfile = () =>
139
+ useAuthStore((state) => ({
140
+ user: state.user,
141
+ profile: state.profile,
142
+ isLoggedIn: state.isLoggedIn,
143
+ }));
144
+
145
+ // Usage in component
146
+ function UserCard() {
147
+ const email = useUserEmail();
148
+ const { profile } = useUserWithProfile();
149
+
150
+ // Only re-renders when email or profile object reference changes
151
+ return <Text>{email}</Text>;
152
+ }
153
+ ```
154
+
155
+ ### Store for Favorites with Toggle
156
+
157
+ ```typescript
158
+ // File: src/store/favoriteFeaturesStore.ts
159
+ import { create } from 'zustand';
160
+ import { persist, createJSONStorage } from 'zustand/middleware';
161
+ import AsyncStorage from '@react-native-async-storage/async-storage';
162
+
163
+ export interface FavoritesState {
164
+ favorites: Record<string, boolean>;
165
+ toggleFavorite: (key: string) => void;
166
+ isFavorite: (key: string) => boolean;
167
+ }
168
+
169
+ export const useFavoritesStore = create<FavoritesState>()(
170
+ persist(
171
+ (set, get) => ({
172
+ favorites: {},
173
+
174
+ toggleFavorite: (key) =>
175
+ set((state) => ({
176
+ favorites: {
177
+ ...state.favorites,
178
+ [key]: !state.favorites[key],
179
+ },
180
+ })),
181
+
182
+ isFavorite: (key) => !!get().favorites[key],
183
+ }),
184
+ {
185
+ name: 'favorites-storage',
186
+ storage: createJSONStorage(() => AsyncStorage),
187
+ }
188
+ )
189
+ );
190
+
191
+ // Selector hooks
192
+ export const useIsFavorite = (key: string) =>
193
+ useFavoritesStore((state) => state.isFavorite(key));
194
+
195
+ export const useToggleFavorite = () =>
196
+ useFavoritesStore((state) => state.toggleFavorite);
197
+
198
+ // Component usage
199
+ function FavoriteButton({ pageKey }: { pageKey: string }) {
200
+ const isFavorite = useIsFavorite(pageKey);
201
+ const toggle = useToggleFavorite();
202
+
203
+ return (
204
+ <Pressable onPress={() => toggle(pageKey)}>
205
+ <Text>{isFavorite ? '⭐' : '☆'}</Text>
206
+ </Pressable>
207
+ );
208
+ }
209
+ ```
210
+
211
+ **From:** PokePages/src/store/favoriteFeaturesStore.ts
212
+
213
+ ## Configuration
214
+
215
+ ### Cross-Platform Storage Setup
216
+
217
+ ```typescript
218
+ // File: src/utils/createCrossPlatformStorage.ts
219
+ import { Platform } from 'react-native';
220
+ import AsyncStorage from '@react-native-async-storage/async-storage';
221
+ import { createJSONStorage } from 'zustand/middleware';
222
+
223
+ export function createCrossPlatformStorage() {
224
+ if (Platform.OS === 'web') {
225
+ return createJSONStorage(() => ({
226
+ getItem: (key) => localStorage.getItem(key),
227
+ setItem: (key, value) => localStorage.setItem(key, value),
228
+ removeItem: (key) => localStorage.removeItem(key),
229
+ }));
230
+ }
231
+
232
+ return createJSONStorage(() => AsyncStorage);
233
+ }
234
+
235
+ // Use in stores
236
+ export const useStore = create<State>()(
237
+ persist(
238
+ (set) => ({ /* state */ }),
239
+ {
240
+ storage: createCrossPlatformStorage(),
241
+ }
242
+ )
243
+ );
244
+ ```
245
+
246
+ ## Best Practices
247
+
248
+ ### ✅ DO
249
+
250
+ 1. **Use selector hooks** to prevent unnecessary re-renders
251
+ ```typescript
252
+ // ✅ GOOD - only subscribes to email
253
+ const email = useAuthStore((state) => state.user?.email);
254
+
255
+ // ❌ BAD - subscribes to entire store
256
+ const { user, profile, session, ... } = useAuthStore();
257
+ ```
258
+
259
+ 2. **Keep stores flat** — avoid nested objects
260
+ ```typescript
261
+ // ✅ GOOD - flat structure
262
+ userId: '123'
263
+ userName: 'alice'
264
+ userEmail: 'alice@example.com'
265
+
266
+ // ❌ BAD - nested (causes unnecessary re-renders)
267
+ user: { id: '123', name: 'alice', email: '...' }
268
+ ```
269
+
270
+ 3. **Use computed properties (getters)** for derived state
271
+ ```typescript
272
+ get isAdult(): boolean {
273
+ return calculateAge(get().profile?.dateOfBirth) >= 18;
274
+ }
275
+ ```
276
+
277
+ 4. **Partial persistence** — only persist necessary fields
278
+ ```typescript
279
+ partialize: (state) => ({
280
+ user: state.user,
281
+ theme: state.theme,
282
+ // Don't persist: loading, errors, temporary UI state
283
+ })
284
+ ```
285
+
286
+ 5. **Split stores** by domain/feature
287
+ ```typescript
288
+ useAuthStore() // auth + user
289
+ useThemeStore() // app theme
290
+ useFavoritesStore() // favorites
291
+ ```
292
+
293
+ ### ❌ DON'T
294
+
295
+ 1. **Don't use context** for everything
296
+ ```typescript
297
+ // ❌ AVOID - causes re-renders of all consumers
298
+ <UserContext.Provider value={{ user, setUser, ... }}>
299
+
300
+ // ✅ USE - only subscribed components re-render
301
+ const user = useUserStore((state) => state.user);
302
+ ```
303
+
304
+ 2. **Don't persist state that changes frequently**
305
+ ```typescript
306
+ // ❌ BAD - persists on every keystroke
307
+ persist((set) => ({
308
+ searchQuery: '',
309
+ setSearchQuery: (q) => set({ searchQuery: q })
310
+ }))
311
+
312
+ // ✅ GOOD - only persist final state
313
+ onChangeText={(q) => dispatch(setSearchQuery(q))} // local only
314
+ ```
315
+
316
+ 3. **Don't store derived data** that can be computed
317
+ ```typescript
318
+ // ❌ BAD - will get out of sync
319
+ user: { id: '1', name: 'alice', email: 'alice@ex.com' }
320
+ userDisplayName: 'alice' // Duplicate!
321
+
322
+ // ✅ GOOD - compute on demand
323
+ get userDisplayName() {
324
+ return get().user?.name;
325
+ }
326
+ ```
327
+
328
+ 4. **Don't forget to handle undefined** from selectors
329
+ ```typescript
330
+ // ❌ RISKY
331
+ const email = useAuthStore((state) => state.user?.email);
332
+ return <Text>{email}</Text>; // Could be undefined
333
+
334
+ // ✅ SAFE
335
+ const email = useAuthStore((state) => state.user?.email);
336
+ return <Text>{email || 'No email'}</Text>;
337
+ ```
338
+
339
+ ## Related Patterns
340
+
341
+ - [Store Organization](./store-organization.md) — Multi-store patterns
342
+ - [Persistence Middleware](./persistence-middleware.md) — AsyncStorage integration
343
+ - [Selector Hooks](./selector-hooks.md) — Performance optimization
344
+
345
+ ---
346
+
347
+ *Pattern extracted from production repositories: PokePages, core-monorepo, time2pay*
348
348
  *Files: PokePages/src\store\authStore.ts, favoriteFeaturesStore.ts*