Skip to content

Performance

Without minDuration
Network responds in 50ms. Causes an ugly UI flash.
With minDuration (600ms)
FlowState prevents UI jitter by enforcing a minimum readable loading time.

Best practices for optimal performance with AsyncFlowState.

Bundle Size

AsyncFlowState is designed to be lightweight:

PackageSize (gzipped)
@asyncflowstate/core~3 KB
@asyncflowstate/react~2 KB
@asyncflowstate/vue~1.5 KB
@asyncflowstate/svelte~1 KB

All packages are tree-shakeable — unused exports are eliminated by your bundler.

Minimizing Re-renders

React

useFlow uses fine-grained subscriptions. Components only re-render when the state properties they read actually change.

tsx
// <i class="fa-solid fa-check"></i> Good — only re-renders when `loading` changes
function SaveButton() {
  const { loading, button } = useFlow(saveData);
  return <button {...button()}>{loading ? "..." : "Save"}</button>;
}

Avoid Creating Flows in Render

tsx
// <i class="fa-solid fa-xmark"></i> Bad — creates a new Flow instance every render
function Component() {
  const flow = useFlow(async () => await fetch(url));
}

// <i class="fa-solid fa-check"></i> Good — stable function reference
const fetchData = async () => await fetch(url);
function Component() {
  const flow = useFlow(fetchData);
}

Loading UX Performance

Prevent Loading Flashes

When an API responds in under 100ms, showing and hiding a spinner causes a jarring flash. Use minDuration:

ts
const flow = useFlow(fastApi, {
  loading: { minDuration: 400 },
});
// Loading state lasts at least 400ms, even if API responds in 50ms

Delay Loading Indicators

For actions that are usually instant, don't show a spinner unless it's actually slow:

ts
const flow = useFlow(quickSave, {
  loading: { delay: 200 },
});
// Loading state only becomes true after 200ms
// If the action completes before 200ms, no spinner appears

Concurrency Best Practices

PatternStrategyWhy
Form submit"keep"Prevent duplicate submissions
Search input"restart"Cancel stale results
File upload"enqueue"Process in order
Data refresh"restart"Always use latest data

Retry Performance

Choose the right backoff strategy:

StrategyServer LoadUser WaitUse Case
"fixed"ConsistentPredictableKnown recovery time
"linear"DecreasingGrowingModerate backoff
"exponential"MinimalCan be longThird-party APIs, rate limits

Production Config

ts
// Recommended production defaults
{
  loading: { minDuration: 400 },
  retry: { maxAttempts: 3, backoff: "exponential", delay: 1000 },
  concurrency: "keep",
}

Built with by AsyncFlowState Contributors
Open Source · MIT License