@mr.dj2u/knowledge 0.1.0

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 (83) hide show
  1. package/dist/content/checklists/ship-test-loop.md +16 -0
  2. package/dist/content/checklists/unified-agent-bundle-validation.md +8 -0
  3. package/dist/content/examples/ship-test-loop.md +13 -0
  4. package/dist/content/examples/unified-agent-bundle-bootstrap.md +8 -0
  5. package/dist/content/guides/animation-performance.md +30 -0
  6. package/dist/content/guides/post-create-onboarding.md +113 -0
  7. package/dist/content/patterns/api/api-routes.md +314 -0
  8. package/dist/content/patterns/api/error-handling.md +311 -0
  9. package/dist/content/patterns/database/drizzle-schema.md +280 -0
  10. package/dist/content/patterns/database/migrations.md +365 -0
  11. package/dist/content/patterns/database/query-organization.md +537 -0
  12. package/dist/content/patterns/database/relations.md +450 -0
  13. package/dist/content/patterns/deployment/build-configuration.md +452 -0
  14. package/dist/content/patterns/deployment/ci-cd-patterns.md +448 -0
  15. package/dist/content/patterns/deployment/environment-config.md +380 -0
  16. package/dist/content/patterns/deployment/hosting-setup.md +425 -0
  17. package/dist/content/patterns/project/configuration-patterns.md +459 -0
  18. package/dist/content/patterns/project/documentation-org.md +506 -0
  19. package/dist/content/patterns/project/folder-structure.md +398 -0
  20. package/dist/content/patterns/project/library-exports.md +465 -0
  21. package/dist/content/patterns/project/monorepo-structure.md +500 -0
  22. package/dist/content/patterns/routing/dynamic-routes.md +221 -0
  23. package/dist/content/patterns/routing/file-based-routing.md +186 -0
  24. package/dist/content/patterns/routing/route-groups.md +429 -0
  25. package/dist/content/patterns/state/persistence-middleware.md +521 -0
  26. package/dist/content/patterns/state/selector-hooks.md +538 -0
  27. package/dist/content/patterns/state/store-organization.md +539 -0
  28. package/dist/content/patterns/state/zustand-patterns.md +348 -0
  29. package/dist/content/patterns/styling/component-styling.md +468 -0
  30. package/dist/content/patterns/styling/responsive-patterns.md +398 -0
  31. package/dist/content/patterns/styling/theme-configuration.md +426 -0
  32. package/dist/content/patterns/styling/uniwind-setup.md +412 -0
  33. package/dist/content/prompts/continue-development.md +27 -0
  34. package/dist/content/prompts/create-expo-super-stack.md +29 -0
  35. package/dist/content/prompts/fix-seo.md +29 -0
  36. package/dist/content/prompts/onboard-new-expo-app.md +11 -0
  37. package/dist/content/prompts/prepare-deploy.md +29 -0
  38. package/dist/content/prompts/project-research-plan.md +29 -0
  39. package/dist/content/prompts/review-expo-project.md +29 -0
  40. package/dist/content/prompts/run-doctor.md +30 -0
  41. package/dist/content/prompts/ship-test-loop.md +24 -0
  42. package/dist/content/reference/create-expo-stack-uniwind.md +29 -0
  43. package/dist/content/reference/doctor-dogfood.md +42 -0
  44. package/dist/content/reference/mcp-sdk-transport.md +30 -0
  45. package/dist/content/reference/package-ci-patterns.md +24 -0
  46. package/dist/content/reference/reference-repo-evacuation.md +31 -0
  47. package/dist/content/resource-index.json +67 -0
  48. package/dist/content/rules/app-folder-architecture.md +13 -0
  49. package/dist/content/rules/env-hygiene.md +9 -0
  50. package/dist/content/rules/seo-metadata.md +7 -0
  51. package/dist/content/rules/ssr-safety.md +9 -0
  52. package/dist/content/skills/api-routes.md +33 -0
  53. package/dist/content/skills/continue-development.md +31 -0
  54. package/dist/content/skills/debugging.md +31 -0
  55. package/dist/content/skills/deployment.md +32 -0
  56. package/dist/content/skills/dev-server-management.md +31 -0
  57. package/dist/content/skills/env-vars.md +32 -0
  58. package/dist/content/skills/expo-router-architecture.md +33 -0
  59. package/dist/content/skills/expo-ssr-safety.md +32 -0
  60. package/dist/content/skills/plugin-creation.md +41 -0
  61. package/dist/content/skills/production-server-patterns.md +31 -0
  62. package/dist/content/skills/project-onboarding.md +31 -0
  63. package/dist/content/skills/research-plan-intake.md +31 -0
  64. package/dist/content/skills/seo-metadata.md +31 -0
  65. package/dist/content/skills/super-stack-startup.md +31 -0
  66. package/dist/content/skills/uniwind-theming.md +32 -0
  67. package/dist/index.d.ts +46 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +369 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/patterns/index.d.ts +78 -0
  72. package/dist/patterns/index.d.ts.map +1 -0
  73. package/dist/patterns/index.js +264 -0
  74. package/dist/patterns/index.js.map +1 -0
  75. package/dist/prompts/index.d.ts +35 -0
  76. package/dist/prompts/index.d.ts.map +1 -0
  77. package/dist/prompts/index.js +270 -0
  78. package/dist/prompts/index.js.map +1 -0
  79. package/dist/skills/index.d.ts +3 -0
  80. package/dist/skills/index.d.ts.map +1 -0
  81. package/dist/skills/index.js +2 -0
  82. package/dist/skills/index.js.map +1 -0
  83. package/package.json +50 -0
@@ -0,0 +1,538 @@
1
+ # Selector Hooks Pattern
2
+
3
+ ## Description
4
+
5
+ Selector hooks extract and memoize specific state values from Zustand stores, preventing unnecessary re-renders when unrelated store state changes. This pattern optimizes performance by ensuring components only re-render when *their specific selected state* changes, not when any store property updates.
6
+
7
+ ## When to Use
8
+
9
+ **Use selector hooks** when:
10
+ - ✅ Component only needs 1-2 properties from store (not entire store)
11
+ - ✅ Large stores with many independent properties
12
+ - ✅ Multiple components accessing different store slices
13
+ - ✅ Preventing cascade re-renders in lists
14
+ - ✅ Optimizing performance-critical components
15
+ - ✅ Creating reusable state accessors
16
+
17
+ ## Core Concepts
18
+
19
+ **The Problem: Store Without Selectors**
20
+ ```typescript
21
+ // ❌ WRONG - Component re-renders when ANY store property changes
22
+ function UserCard() {
23
+ const store = useAuthStore(); // Entire store destructured
24
+ // Component re-renders when user, profile, session, loading, error change
25
+ return <Text>{store.user?.email}</Text>;
26
+ }
27
+ ```
28
+
29
+ **The Solution: Selector Hooks**
30
+ ```typescript
31
+ // ✅ RIGHT - Component only re-renders when user changes
32
+ function UserCard() {
33
+ const userEmail = useAuthStore((state) => state.user?.email);
34
+ // Component re-renders ONLY when email changes
35
+ return <Text>{userEmail}</Text>;
36
+ }
37
+ ```
38
+
39
+ **Selector Execution:**
40
+ 1. Component calls selector hook
41
+ 2. Selector function receives entire state
42
+ 3. Selector returns only needed property(s)
43
+ 4. Zustand compares returned value with previous
44
+ 5. Re-render only if value changed (shallow equality)
45
+
46
+ ## Code Examples
47
+
48
+ ### Basic Selector Pattern
49
+
50
+ ```typescript
51
+ // File: src/store/authStore.ts
52
+ import { create } from 'zustand';
53
+
54
+ interface AuthState {
55
+ user: User | null;
56
+ profile: Profile | null;
57
+ isLoggedIn: boolean;
58
+ loading: boolean;
59
+ error: string | null;
60
+
61
+ setUser: (user: User | null) => void;
62
+ login: (email: string, password: string) => Promise<void>;
63
+ }
64
+
65
+ export const useAuthStore = create<AuthState>((set) => ({
66
+ user: null,
67
+ profile: null,
68
+ isLoggedIn: false,
69
+ loading: false,
70
+ error: null,
71
+
72
+ setUser: (user) => set({ user, isLoggedIn: !!user }),
73
+ login: async (email, password) => {
74
+ set({ loading: true });
75
+ // ...
76
+ },
77
+ }));
78
+
79
+ // File: src/hooks/useAuth.ts
80
+ /**
81
+ * Individual selector hooks for auth state
82
+ * Each hook selects one specific property
83
+ */
84
+
85
+ export const useUserEmail = () => {
86
+ return useAuthStore((state) => state.user?.email);
87
+ };
88
+
89
+ export const useIsLoggedIn = () => {
90
+ return useAuthStore((state) => state.isLoggedIn);
91
+ };
92
+
93
+ export const useAuthLoading = () => {
94
+ return useAuthStore((state) => state.loading);
95
+ };
96
+
97
+ export const useAuthError = () => {
98
+ return useAuthStore((state) => state.error);
99
+ };
100
+
101
+ export const useUserProfile = () => {
102
+ return useAuthStore((state) => state.profile);
103
+ };
104
+ ```
105
+
106
+ ### Composite Selector Pattern
107
+
108
+ ```typescript
109
+ // File: src/hooks/useAuth.ts
110
+
111
+ /**
112
+ * Combine multiple related properties
113
+ * Useful when component needs several related values
114
+ */
115
+ export const useAuthStatus = () => {
116
+ return useAuthStore((state) => ({
117
+ isLoggedIn: state.isLoggedIn,
118
+ loading: state.loading,
119
+ error: state.error,
120
+ }));
121
+ };
122
+
123
+ /**
124
+ * For object properties, use shallow equality check
125
+ */
126
+ import { useShallow } from 'zustand/react';
127
+
128
+ export const useUserData = () => {
129
+ return useAuthStore(
130
+ useShallow((state) => ({
131
+ user: state.user,
132
+ profile: state.profile,
133
+ }))
134
+ );
135
+ };
136
+
137
+ /**
138
+ * Computed/derived selectors
139
+ * Create values on-the-fly from state
140
+ */
141
+ export const useIsAdmin = () => {
142
+ return useAuthStore((state) => {
143
+ return state.profile?.role === 'admin';
144
+ });
145
+ };
146
+
147
+ export const useUserDisplayName = () => {
148
+ return useAuthStore((state) => {
149
+ return state.user?.displayName || state.user?.email || 'Anonymous';
150
+ });
151
+ };
152
+ ```
153
+
154
+ ### Advanced: Memoized Selectors
155
+
156
+ ```typescript
157
+ // File: src/hooks/useAuth.ts
158
+ import { useMemo } from 'react';
159
+
160
+ /**
161
+ * Selector factory - returns memoized selector function
162
+ * Useful for passing parameters to selectors
163
+ */
164
+ export function useUserById(userId: string) {
165
+ return useAuthStore(
166
+ useMemo(
167
+ () => (state) => {
168
+ // Selector only recreated if userId changes
169
+ if (state.user?.id === userId) {
170
+ return state.user;
171
+ }
172
+ return null;
173
+ },
174
+ [userId]
175
+ )
176
+ );
177
+ }
178
+
179
+ /**
180
+ * Selector with default value
181
+ */
182
+ export const useThemePreference = (defaultTheme = 'auto') => {
183
+ return useAuthStore((state) => state.profile?.themePreference " defaultTheme);
184
+ };
185
+
186
+ /**
187
+ * Conditional selectors
188
+ */
189
+ export const useLoggedInUserProfile = () => {
190
+ return useAuthStore((state) => {
191
+ // Only return if user is logged in
192
+ if (state.isLoggedIn && state.user && state.profile) {
193
+ return state.profile;
194
+ }
195
+ return null;
196
+ });
197
+ };
198
+ ```
199
+
200
+ ### Action Selector Pattern
201
+
202
+ ```typescript
203
+ // File: src/store/authStore.ts & hooks/useAuth.ts
204
+
205
+ interface AuthState {
206
+ // ... state properties
207
+ user: User | null;
208
+ profile: Profile | null;
209
+
210
+ // Actions
211
+ setUser: (user: User | null) => void;
212
+ login: (email: string, password: string) => Promise<void>;
213
+ logout: () => Promise<void>;
214
+ updateProfile: (profile: Partial<Profile>) => Promise<void>;
215
+ }
216
+
217
+ export const useAuthStore = create<AuthState>((set) => ({
218
+ // ... state
219
+ setUser: (user) => set({ user }),
220
+ login: async (email, password) => {
221
+ // ...
222
+ },
223
+ logout: async () => {
224
+ // ...
225
+ },
226
+ updateProfile: async (profile) => {
227
+ // ...
228
+ },
229
+ }));
230
+
231
+ /**
232
+ * Selector for actions
233
+ * Actions are stable references, no memoization needed
234
+ */
235
+ export const useAuthActions = () => {
236
+ return useAuthStore((state) => ({
237
+ login: state.login,
238
+ logout: state.logout,
239
+ setUser: state.setUser,
240
+ }));
241
+ };
242
+
243
+ /**
244
+ * Combined selectors: state + actions
245
+ */
246
+ export const useAuthContext = () => {
247
+ return useAuthStore((state) => ({
248
+ // State
249
+ user: state.user,
250
+ isLoggedIn: state.isLoggedIn,
251
+ loading: state.loading,
252
+ error: state.error,
253
+
254
+ // Actions
255
+ login: state.login,
256
+ logout: state.logout,
257
+ setUser: state.setUser,
258
+ }));
259
+ };
260
+ ```
261
+
262
+ ### List/Array Selectors
263
+
264
+ ```typescript
265
+ // File: src/store/postsStore.ts & hooks/usePosts.ts
266
+
267
+ interface PostsState {
268
+ posts: Post[];
269
+ selectedPostId: string | null;
270
+ filter: 'all' | 'favorites' | 'archived';
271
+
272
+ addPost: (post: Post) => void;
273
+ deletePost: (id: string) => void;
274
+ selectPost: (id: string) => void;
275
+ setFilter: (filter: 'all' | 'favorites' | 'archived') => void;
276
+ }
277
+
278
+ export const usePostsStore = create<PostsState>((set) => ({
279
+ posts: [],
280
+ selectedPostId: null,
281
+ filter: 'all',
282
+
283
+ addPost: (post) => set((state) => ({ posts: [...state.posts, post] })),
284
+ deletePost: (id) =>
285
+ set((state) => ({
286
+ posts: state.posts.filter((p) => p.id !== id),
287
+ })),
288
+ selectPost: (id) => set({ selectedPostId: id }),
289
+ setFilter: (filter) => set({ filter }),
290
+ }));
291
+
292
+ /**
293
+ * Filter and map selectors
294
+ */
295
+ export const useFavoritePosts = () => {
296
+ return usePostsStore((state) =>
297
+ state.posts.filter((post) => post.isFavorite)
298
+ );
299
+ };
300
+
301
+ export const useFilteredPosts = () => {
302
+ return usePostsStore((state) => {
303
+ switch (state.filter) {
304
+ case 'favorites':
305
+ return state.posts.filter((p) => p.isFavorite);
306
+ case 'archived':
307
+ return state.posts.filter((p) => p.archived);
308
+ default:
309
+ return state.posts;
310
+ }
311
+ });
312
+ };
313
+
314
+ /**
315
+ * Sorted selectors
316
+ */
317
+ export const usePostsSortedByDate = () => {
318
+ return usePostsStore((state) =>
319
+ [...state.posts].sort(
320
+ (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
321
+ )
322
+ );
323
+ };
324
+
325
+ /**
326
+ * Count selectors
327
+ */
328
+ export const usePostCount = () => {
329
+ return usePostsStore((state) => state.posts.length);
330
+ };
331
+
332
+ export const useFavoritePostCount = () => {
333
+ return usePostsStore((state) => state.posts.filter((p) => p.isFavorite).length);
334
+ };
335
+
336
+ /**
337
+ * Specific post selector
338
+ */
339
+ export const usePostById = (postId: string) => {
340
+ return usePostsStore((state) =>
341
+ state.posts.find((p) => p.id === postId)
342
+ );
343
+ };
344
+
345
+ export const useSelectedPost = () => {
346
+ return usePostsStore((state) => {
347
+ if (!state.selectedPostId) return null;
348
+ return state.posts.find((p) => p.id === state.selectedPostId) " null;
349
+ });
350
+ };
351
+ ```
352
+
353
+ ## Performance Optimization
354
+
355
+ ### Equality Checking
356
+
357
+ ```typescript
358
+ // File: src/hooks/useAuth.ts
359
+ import { useShallow } from 'zustand/react';
360
+
361
+ /**
362
+ * Default: Shallow equality for objects
363
+ */
364
+ function Component() {
365
+ // Without useShallow - object reference changes every time
366
+ const user = useAuthStore((state) => ({
367
+ id: state.user?.id,
368
+ email: state.user?.email,
369
+ })); // Re-renders if ANY store property changes
370
+ }
371
+
372
+ /**
373
+ * With useShallow - values are compared, not reference
374
+ */
375
+ function Component() {
376
+ const user = useAuthStore(
377
+ useShallow((state) => ({
378
+ id: state.user?.id,
379
+ email: state.user?.email,
380
+ }))
381
+ ); // Re-renders only if id or email changes
382
+ }
383
+ ```
384
+
385
+ ### Subscription Pattern
386
+
387
+ ```typescript
388
+ // File: src/utils/storeSubscription.ts
389
+ import { useEffect, useRef } from 'react';
390
+
391
+ /**
392
+ * Subscribe to specific state changes
393
+ * Useful for side effects triggered by state changes
394
+ */
395
+ export function useStoreSubscription<T>(
396
+ selector: (state: any) => T,
397
+ onChange: (value: T) => void
398
+ ) {
399
+ const previousValue = useRef<T>();
400
+
401
+ useEffect(() => {
402
+ const unsubscribe = useAuthStore.subscribe(
403
+ selector,
404
+ (value) => {
405
+ if (previousValue.current !== value) {
406
+ previousValue.current = value;
407
+ onChange(value);
408
+ }
409
+ }
410
+ );
411
+
412
+ return unsubscribe;
413
+ }, [selector, onChange]);
414
+ }
415
+
416
+ // Usage
417
+ function Component() {
418
+ useStoreSubscription(
419
+ (state) => state.isLoggedIn,
420
+ (isLoggedIn) => {
421
+ if (isLoggedIn) {
422
+ console.log('User logged in!');
423
+ }
424
+ }
425
+ );
426
+ }
427
+ ```
428
+
429
+ ## Selector Best Practices
430
+
431
+ ### ✅ DO
432
+
433
+ 1. **Create specific selectors for each property**
434
+ ```typescript
435
+ // ✅ RIGHT
436
+ export const useUserEmail = () => useAuthStore((s) => s.user?.email);
437
+ export const useIsLoggedIn = () => useAuthStore((s) => s.isLoggedIn);
438
+
439
+ function Component() {
440
+ const email = useUserEmail(); // Only re-renders if email changes
441
+ }
442
+ ```
443
+
444
+ 2. **Use selector hooks in components**
445
+ ```typescript
446
+ // ✅ RIGHT
447
+ export const useUserData = () =>
448
+ useAuthStore(useShallow((s) => ({ user: s.user, profile: s.profile })));
449
+
450
+ function Component() {
451
+ const { user, profile } = useUserData();
452
+ }
453
+ ```
454
+
455
+ 3. **Memoize complex selectors**
456
+ ```typescript
457
+ // ✅ RIGHT
458
+ export const useFilteredAndSorted = () => {
459
+ return usePostsStore((state) =>
460
+ state.posts
461
+ .filter((p) => p.published)
462
+ .sort((a, b) => b.date - a.date)
463
+ );
464
+ };
465
+ ```
466
+
467
+ ### ❌ DON'T
468
+
469
+ 1. **Don't destructure entire store in component**
470
+ ```typescript
471
+ // ❌ WRONG - Re-renders on any store change
472
+ function Component() {
473
+ const { user, profile, loading, error, ... } = useAuthStore();
474
+ }
475
+ ```
476
+
477
+ 2. **Don't create selectors inline**
478
+ ```typescript
479
+ // ❌ WRONG - Selector recreated every render
480
+ function Component() {
481
+ const email = useAuthStore(
482
+ (state) => state.user?.email // NEW function every render
483
+ );
484
+ }
485
+
486
+ // ✅ RIGHT - Extract to hook or useMemo
487
+ export const useUserEmail = () => useAuthStore((s) => s.user?.email);
488
+ ```
489
+
490
+ 3. **Don't perform expensive operations in selectors**
491
+ ```typescript
492
+ // ❌ WRONG - Heavy computation on every store change
493
+ const processedData = useAuthStore((state) => {
494
+ return state.data.map(/* heavy processing */).sort().filter();
495
+ });
496
+
497
+ // ✅ RIGHT - Use useMemo or memoized selector
498
+ export const useProcessedData = () => {
499
+ return useAuthStore((state) => state.processedData); // Pre-computed
500
+ };
501
+ ```
502
+
503
+ ## Comparison: With vs Without Selectors
504
+
505
+ ### Without Selectors (❌ Performance Issue)
506
+ ```typescript
507
+ function UserCard() {
508
+ const { user, profile, isLoggedIn, loading, error } = useAuthStore();
509
+ // Re-renders when ANY property changes
510
+ return <Text>{user?.email}</Text>;
511
+ }
512
+ ```
513
+
514
+ ### With Selectors (✅ Optimized)
515
+ ```typescript
516
+ export const useUserEmail = () => useAuthStore((s) => s.user?.email);
517
+
518
+ function UserCard() {
519
+ const email = useUserEmail();
520
+ // Re-renders ONLY when email changes
521
+ return <Text>{email}</Text>;
522
+ }
523
+ ```
524
+
525
+ **Performance Impact:**
526
+ - Without selectors: UserCard re-renders when loading, error, profile change (unnecessary)
527
+ - With selectors: UserCard re-renders only when email changes (efficient)
528
+
529
+ ## Related Patterns
530
+
531
+ - [Store Organization](./store-organization.md) — Multiple focused stores
532
+ - [Persistence Middleware](./persistence-middleware.md) — State persistence
533
+ - [Zustand Patterns](./zustand-patterns.md) — Zustand fundamentals
534
+
535
+ ---
536
+
537
+ *Pattern extracted from production repositories: core-monorepo, PokePages, DJsPortfolio*
538
+ *Files: src/hooks/ directory, src/store/ with custom selectors*