Skip to content

Latest commit

 

History

History

README.md

AsyncFlowState Logo

@asyncflowstate/react v3.0.0 Stable

React hooks and helpers for elegant, accessible async UI behavior management.

Documentation License: MIT NPM Version


Installation

npm install @asyncflowstate/react
# or
pnpm add @asyncflowstate/react

This package depends on @asyncflowstate/core which will be installed automatically.

Quick Start

import { useFlow } from "@asyncflowstate/react";

function SaveButton() {
  const flow = useFlow(async (data) => {
    return await api.save(data);
  });

  return (
    <button {...flow.button()}>
      {flow.loading ? "Saving..." : "Save Changes"}
    </button>
  );
}

Global Configuration with FlowProvider

Use FlowProvider to set default options for all flows in your application. This is perfect for global error handling, retry policies, and UX settings.

import { FlowProvider, useFlow } from "@asyncflowstate/react";

function App() {
  return (
    <FlowProvider
      config={{
        onError: (err) => toast.error(err.message),
        retry: { maxAttempts: 3, backoff: "exponential" },
        loading: { minDuration: 300 },
      }}
    >
      <YourApp />
    </FlowProvider>
  );
}

// All flows inside will inherit the global config
function YourApp() {
  const flow = useFlow(saveData); // Automatically has retry + error handling

  return <button {...flow.button()}>Save</button>;
}

Benefits of FlowProvider

  • DRY Principle: Define error handlers, retry logic, and UX settings once
  • Consistency: Ensure all async actions behave the same way
  • Flexibility: Local options can override global settings
  • Nested Providers: Different sections can have different configurations
<FlowProvider config={{ retry: { maxAttempts: 2 } }}>
  <MainApp />

  {/* Admin section needs more retries */}
  <FlowProvider config={{ retry: { maxAttempts: 5 } }}>
    <AdminPanel />
  </FlowProvider>
</FlowProvider>

See FlowProvider examples for more patterns.

Comprehensive Examples

1. The Classic: Optimistic UI with Deep-Diff Rollback

Update your UI instantly and trust AsyncFlowState to revert to the exact previous state if the network fails.

import { useFlow } from "@asyncflowstate/react";

function LikeButton({ post }) {
  const flow = useFlow(api.likePost, {
    // 1. Update state immediately
    optimisticResult: (prev) => ({
      ...prev,
      likes: prev.likes + 1,
      isLiked: true,
    }),
    // 2. Automatically revert on failure
    rollbackOnError: true,
    onSuccess: () => toast.success("Liked!"),
    onError: () => toast.error("Connection failed. Reverting..."),
  });

  return (
    <button {...flow.button({ onClick: () => flow.execute(post.id) })}>
      {flow.data.isLiked ? "❤️" : "🤍"} {flow.data.likes}
    </button>
  );
}

2. Enterprise Forms: Zod Validation & Auto-Extraction

Stop manually mapping e.target.value. Use built-in schema validation and automatic focus management.

import { z } from "zod";
import { useFlow } from "@asyncflowstate/react";

const schema = z.object({
  email: z.string().email("Invalid email address"),
  password: z.string().min(8, "Password too short"),
});

function LoginForm() {
  const flow = useFlow(auth.login, {
    onSuccess: () => navigate("/dashboard"),
  });

  return (
    <form
      {...flow.form({ schema, extractFormData: true, resetOnSuccess: true })}
    >
      <input name="email" placeholder="Email" />
      {flow.fieldErrors.email && (
        <p className="error">{flow.fieldErrors.email}</p>
      )}

      <input name="password" type="password" placeholder="Password" />
      {flow.fieldErrors.password && (
        <p className="error">{flow.fieldErrors.password}</p>
      )}

      <button type="submit" disabled={flow.loading}>
        {flow.loading ? "Logging in..." : "Login"}
      </button>

      {/* Auto-focuses on error */}
      {flow.error && <div ref={flow.errorRef}>{flow.error.message}</div>}
    </form>
  );
}

3. AI-Powered: Predictive Intent & Flow DNA

Pre-warm your flows before the user even clicks. AsyncFlowState learns from hover patterns to eliminate perceived latency.

import { useFlow } from "@asyncflowstate/react";

function ProductCard({ productId }) {
  const flow = useFlow(api.getDetails, {
    predictive: {
      prefetchOnHover: true, // Learns and pre-warms the flow
      threshold: 0.8, // Confidence threshold
    },
  });

  return (
    <div onMouseEnter={flow.button().onMouseEnter} className="card">
      <h3>Product {productId}</h3>
      <button onClick={() => flow.execute(productId)}>
        {flow.status === "prewarmed" ? "Instant View" : "View Details"}
      </button>
    </div>
  );
}

4. Cross-Tab Sync: Real-Time Coordination

Keep your application state consistent across every open tab without a backend websocket.

const flow = useFlow(api.updateSettings, {
  // Syncs loading status and data across all tabs automatically
  crossTab: {
    sync: true,
    channel: "user-settings",
  },
});

5. Multi-Step Workflows: useFlowSequence

Manage complex, interdependent async steps with a single source of truth for progress and errors.

import { useFlowSequence } from "@asyncflowstate/react";

function SetupWizard() {
  const sequence = useFlowSequence([
    { name: "Create Account", flow: accountFlow },
    { name: "Verify Email", flow: emailFlow, mapInput: (acc) => acc.email },
    { name: "Sync Data", flow: syncFlow },
  ]);

  return (
    <div>
      <progress value={sequence.progress} max="100" />
      <p>Current Step: {sequence.currentStep?.name}</p>
      <button onClick={() => sequence.execute()}>Start Setup</button>
    </div>
  );
}

New in v3.0

  • Flow DNA: AI-driven state that optimizes behavior based on user patterns.
  • Ambient Intelligence: Background orchestration that pre-empts async failures.
  • Speculative Execution: Predicted user intent for zero-latency interactions.
  • Emotional UX Components: Skeleton states and transitions that adapt to app load.
  • Collaborative Hooks: Real-time multi-user state synchronization.
  • Edge-First Fetching: Native support for edge-optimized data flows.
  • Temporal Debugging: Replay any async sequence with full state fidelity.
  • Telemetry Dashboard: Live monitoring of all application flows.

Monitoring & Debugging

FlowDebugger (Timeline View)

A powerful drop-in component to visualize all async activity. Features a Timeline/Gantt view to identify bottlenecks and parallel execution order.

import { FlowDebugger } from "@asyncflowstate/react";

// Add it once at the root
<FlowDebugger />;

FlowNotificationProvider

Catch success or error events from ANY flow globally.

import { FlowNotificationProvider } from "@asyncflowstate/react";

<FlowNotificationProvider
  onSuccess={(e) => toast.success(`${e.flowName} completed!`)}
  onError={(e) => toast.error(`${e.flowName} failed: ${e.state.error.message}`)}
>
  <App />
</FlowNotificationProvider>;

API Reference

useFlow<TData, TError, TArgs>(action, options?)

Returns

{
  // State
  status: 'idle' | 'loading' | 'success' | 'error';
  data: TData | null;
  error: TError | null;
  loading: boolean;      // Respects loading.delay
  progress: number;      // 0-100
  fieldErrors: Record<string, string>;

  // Actions
  execute: (...args: TArgs) => Promise<TData | undefined>;
  reset: () => void;
  cancel: () => void;
  setProgress: (val: number) => void;

  // Helpers & Components
  button: (props?) => ButtonHTMLAttributes;
  form: (props?) => FormHTMLAttributes;
  LiveRegion: React.ComponentType;
  errorRef: React.RefObject<any>;
}

License

MIT © AsyncFlowState Contributors