mirror of
https://github.com/prdlk/dotfiles.git
synced 2026-11-03 19:37:52 +00:00
- 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
4.1 KiB
4.1 KiB
mut-mutation-state: Use useMutationState for Cross-Component Mutation Tracking
Priority: MEDIUM
Explanation
useMutationState allows you to access mutation state from anywhere in your component tree, not just where useMutation was called. Use it to show loading indicators, display optimistic updates, or track pending mutations across components.
Bad Example
// Prop drilling mutation state
function App() {
const mutation = useMutation({ mutationFn: createPost })
return (
<div>
<Header isPending={mutation.isPending} />
<Sidebar isPending={mutation.isPending} />
<Content mutation={mutation} />
<Footer isPending={mutation.isPending} />
</div>
)
}
// Or using context for every mutation
const MutationContext = createContext<UseMutationResult | null>(null)
Good Example
// Define mutation with a key
const useCreatePost = () => useMutation({
mutationKey: ['create-post'],
mutationFn: createPost,
})
// In the component that triggers mutation
function CreatePostButton() {
const mutation = useCreatePost()
return (
<button onClick={() => mutation.mutate(newPost)}>
Create Post
</button>
)
}
// In any other component - track mutation state
function GlobalLoadingIndicator() {
const pendingMutations = useMutationState({
filters: { status: 'pending' },
select: (mutation) => mutation.state.variables,
})
if (pendingMutations.length === 0) return null
return (
<div className="global-loading">
Saving {pendingMutations.length} item(s)...
</div>
)
}
Good Example: Optimistic UI in Separate Component
// Mutation defined in form
function TodoForm() {
const createTodo = useMutation({
mutationKey: ['create-todo'],
mutationFn: (todo: NewTodo) => api.createTodo(todo),
})
return <form onSubmit={...}>...</form>
}
// Optimistic display in list (different component)
function TodoList() {
const { data: todos } = useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
// Get pending todo creations
const pendingTodos = useMutationState({
filters: {
mutationKey: ['create-todo'],
status: 'pending',
},
select: (mutation) => mutation.state.variables as NewTodo,
})
return (
<ul>
{/* Existing todos */}
{todos?.map(todo => (
<TodoItem key={todo.id} todo={todo} />
))}
{/* Optimistic todos (pending creation) */}
{pendingTodos.map((todo, index) => (
<TodoItem
key={`pending-${index}`}
todo={{ ...todo, id: `temp-${index}` }}
isPending
/>
))}
</ul>
)
}
Good Example: Track Specific Mutations
function PostActions({ postId }: { postId: string }) {
// Track if THIS post is being deleted
const isDeletingThisPost = useMutationState({
filters: {
mutationKey: ['delete-post', postId],
status: 'pending',
},
select: () => true,
}).length > 0
// Track if THIS post is being updated
const isUpdatingThisPost = useMutationState({
filters: {
mutationKey: ['update-post', postId],
status: 'pending',
},
select: () => true,
}).length > 0
return (
<div>
<button disabled={isDeletingThisPost || isUpdatingThisPost}>
{isDeletingThisPost ? 'Deleting...' : 'Delete'}
</button>
</div>
)
}
Filters Reference
useMutationState({
filters: {
mutationKey: ['key'], // Match mutation key
status: 'pending', // 'idle' | 'pending' | 'success' | 'error'
predicate: (mutation) => bool, // Custom filter function
},
select: (mutation) => {
// Transform each matching mutation
// mutation.state contains: variables, data, error, status, etc.
return mutation.state.variables
},
})
Context
- Requires
mutationKeyon mutations you want to track - Returns array of selected values from matching mutations
- Updates reactively as mutations progress
- Use
statusfilter to track pending/success/error states - Enables optimistic UI without prop drilling
- Pairs with
mutationKeyarrays for granular tracking (e.g.,['delete-post', postId])