Action props for reusable components, encapsulate transitions and optimistic state.
Design components should handle their own in-between states internally—optimistic updates, pending indicators, transitions—rather than pushing that complexity to every consumer. The pattern: pass the action to perform, let the component handle the coordination.
This creates reusable components that work consistently across your app. Parents don't need to know about transitions or optimistic state—they just pass what should happen.
A tablist that handles its own optimistic updates and transitions:
'use client';
import { useOptimistic, useTransition } from 'react';
type Props = {
tabs: { value: string; label: string }[];
activeTab: string;
changeAction?: (value: string) => void | Promise<void>;
};
export function TabList({ tabs, activeTab, changeAction }: Props) {
const [optimisticTab, setOptimisticTab] = useOptimistic(activeTab);
const [isPending, startTransition] = useTransition();
function handleTabChange(value: string) {
startTransition(async () => {
setOptimisticTab(value);
await changeAction?.(value);
});
}
return (
<Tabs value={optimisticTab} onValueChange={handleTabChange}>
<TabsList>
{tabs.map(tab => (
<TabsTrigger key={tab.value} value={tab.value}>
{tab.label}
</TabsTrigger>
))}
</TabsList>
{isPending && <Spinner />}
</Tabs>
);
}The component owns:
Parents become simple—just pass the action:
'use client';
import { useRouter } from 'next/navigation';
export function PostTabs({ currentFilter, currentSort }) {
const router = useRouter();
returnThe parent doesn't import useTransition, doesn't manage optimistic state, doesn't show a spinner—that's all encapsulated.
Suffix action props with "Action" to distinguish them from regular callbacks:
changeAction — for state changessubmitAction — for form submissionsdeleteAction — for deletionsThis signals that the function may be async and will be wrapped in a transition.
Design components own their in-between states. Parents pass what should happen; components handle how it looks while happening.