mirror of
https://github.com/prdlk/dotfiles.git
synced 2026-11-05 04:08:03 +00:00
shell: fish functions -> ~/.local/bin executables + bash/zsh ports; manage ~/.agents
- 16 cross-shell utilities converted to sh/bash chezmoi executables: ai c2p cp-appid extract_agents fab gdc gh-sonr-org-migrate ghg-clone ghn gho git-summary launch_omp_livediff_overlay lc-elir mdcp mdp pj (ghg-clone not named ghg: unrelated cargo binary owns that name) - cwd/history helpers stay per-shell: yy c cd clip-last + ghg/ghn/gho cd-wrappers in bash/functions/ and zsh/functions/, loaded by rc files - fish keeps only shell-state functions; converted ones now hit PATH - cp-appid ignore gating moved to .local/bin path - dot_agents/skills: 82 skills materialized from dotstate storage so dot_claude skill symlinks resolve on fresh bootstrap; dotstate profile/symlinks.json released .agents/skills .bashrc .zshrc
This commit is contained in:
1 parent
6776366ce6
commit
6406208b35
637 files changed
+100297
-497
No files matched your search
+178
@@ -0,0 +1,178 @@
|
||||
# flow-loader-query-pattern: Use Loaders with ensureQueryData
|
||||
|
||||
## Priority: HIGH
|
||||
|
||||
## Explanation
|
||||
|
||||
The recommended pattern combines TanStack Router's loaders with TanStack Query's `ensureQueryData`. Loaders prefetch data during navigation, while Query manages caching and updates. Use `useSuspenseQuery` in components since data is guaranteed.
|
||||
|
||||
## Bad Example
|
||||
|
||||
```tsx
|
||||
// Only using Query in component - loading waterfall
|
||||
function PostsPage() {
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey: ['posts'],
|
||||
queryFn: fetchPosts,
|
||||
})
|
||||
|
||||
if (isLoading) return <Loading />
|
||||
return <PostList posts={data} />
|
||||
}
|
||||
|
||||
// Only using loader - no cache management
|
||||
export const Route = createFileRoute('/posts')({
|
||||
loader: async () => {
|
||||
const posts = await fetchPosts() // Not cached
|
||||
return { posts }
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
## Good Example
|
||||
|
||||
```tsx
|
||||
// lib/queries/posts.ts - Define queryOptions
|
||||
import { queryOptions } from '@tanstack/react-query'
|
||||
|
||||
export const postQueries = {
|
||||
all: () => queryOptions({
|
||||
queryKey: ['posts'],
|
||||
queryFn: fetchPosts,
|
||||
staleTime: 5 * 60 * 1000,
|
||||
}),
|
||||
detail: (id: string) => queryOptions({
|
||||
queryKey: ['posts', id],
|
||||
queryFn: () => fetchPost(id),
|
||||
staleTime: 5 * 60 * 1000,
|
||||
}),
|
||||
}
|
||||
|
||||
// routes/posts.tsx
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { postQueries } from '@/lib/queries/posts'
|
||||
|
||||
export const Route = createFileRoute('/posts')({
|
||||
loader: async ({ context: { queryClient } }) => {
|
||||
// Prefetch in loader - runs during navigation
|
||||
await queryClient.ensureQueryData(postQueries.all())
|
||||
},
|
||||
component: PostsPage,
|
||||
})
|
||||
|
||||
function PostsPage() {
|
||||
// Data guaranteed by loader - no loading state needed
|
||||
const { data: posts } = useSuspenseQuery(postQueries.all())
|
||||
|
||||
return <PostList posts={posts} />
|
||||
}
|
||||
|
||||
// routes/posts/$postId.tsx
|
||||
export const Route = createFileRoute('/posts/$postId')({
|
||||
loader: async ({ params, context: { queryClient } }) => {
|
||||
await queryClient.ensureQueryData(postQueries.detail(params.postId))
|
||||
},
|
||||
component: PostDetailPage,
|
||||
})
|
||||
|
||||
function PostDetailPage() {
|
||||
const { postId } = Route.useParams()
|
||||
const { data: post } = useSuspenseQuery(postQueries.detail(postId))
|
||||
|
||||
return <PostContent post={post} />
|
||||
}
|
||||
```
|
||||
|
||||
## Good Example: Parallel Data Loading
|
||||
|
||||
```tsx
|
||||
export const Route = createFileRoute('/dashboard')({
|
||||
loader: async ({ context: { queryClient } }) => {
|
||||
// Load multiple queries in parallel
|
||||
await Promise.all([
|
||||
queryClient.ensureQueryData(statsQueries.overview()),
|
||||
queryClient.ensureQueryData(activityQueries.recent()),
|
||||
queryClient.ensureQueryData(userQueries.current()),
|
||||
])
|
||||
},
|
||||
component: DashboardPage,
|
||||
})
|
||||
|
||||
function DashboardPage() {
|
||||
// All data ready - no loading states
|
||||
const { data: stats } = useSuspenseQuery(statsQueries.overview())
|
||||
const { data: activity } = useSuspenseQuery(activityQueries.recent())
|
||||
const { data: user } = useSuspenseQuery(userQueries.current())
|
||||
|
||||
return (
|
||||
<Dashboard
|
||||
stats={stats}
|
||||
activity={activity}
|
||||
user={user}
|
||||
/>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Good Example: Optional Prefetch with Non-Critical Data
|
||||
|
||||
```tsx
|
||||
export const Route = createFileRoute('/posts/$postId')({
|
||||
loader: async ({ params, context: { queryClient } }) => {
|
||||
// Critical data - await it
|
||||
await queryClient.ensureQueryData(postQueries.detail(params.postId))
|
||||
|
||||
// Non-critical - prefetch but don't await
|
||||
queryClient.prefetchQuery(postQueries.comments(params.postId))
|
||||
queryClient.prefetchQuery(postQueries.related(params.postId))
|
||||
},
|
||||
component: PostPage,
|
||||
})
|
||||
|
||||
function PostPage() {
|
||||
const { postId } = Route.useParams()
|
||||
|
||||
// Critical - guaranteed by loader
|
||||
const { data: post } = useSuspenseQuery(postQueries.detail(postId))
|
||||
|
||||
// Non-critical - may still be loading
|
||||
const { data: comments, isLoading: commentsLoading } = useQuery(
|
||||
postQueries.comments(postId)
|
||||
)
|
||||
|
||||
return (
|
||||
<article>
|
||||
<PostContent post={post} />
|
||||
{commentsLoading ? <CommentsSkeleton /> : <Comments data={comments} />}
|
||||
</article>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Data Flow Summary
|
||||
|
||||
```
|
||||
Navigation Starts
|
||||
↓
|
||||
Router matches route
|
||||
↓
|
||||
loader() executes
|
||||
↓
|
||||
ensureQueryData() checks cache
|
||||
↓
|
||||
Fresh cache? → Return cached Stale/missing? → Fetch and cache
|
||||
↓ ↓
|
||||
Route renders Route renders
|
||||
↓ ↓
|
||||
useSuspenseQuery returns data useSuspenseQuery returns data
|
||||
```
|
||||
|
||||
## Context
|
||||
|
||||
- `ensureQueryData` respects staleTime - won't refetch fresh data
|
||||
- `useSuspenseQuery` throws promise to Suspense if data missing
|
||||
- Loaders enable preloading on link hover
|
||||
- This pattern eliminates loading waterfalls
|
||||
- Use `useQuery` for non-critical data that can load after render
|
||||
- Query invalidation and background updates still work normally
|
||||
Reference in new issue
Block a user