complex-state-management

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Complex State Management Without External Libraries

无需外部库的复杂状态管理

Production patterns for managing complex application state in React without Redux, Zustand, or other state libraries. Includes multi-stage loading, command patterns, refs for performance, and parallel data fetching.
无需Redux、Zustand或其他状态库,在React中管理复杂应用状态的生产级模式。包含多阶段加载、命令模式、基于refs的性能优化以及并行数据获取。

When to use this skill

何时使用该方案

  • Building complex UIs with many interconnected states
  • Need loading stages and progress tracking
  • Implementing command patterns for centralized control
  • Managing real-time updates and background operations
  • Want to avoid Redux/Zustand overhead
  • Building video players, editors, or multi-step flows
  • Need precise performance control with refs
  • 构建包含大量互联状态的复杂UI
  • 需要加载阶段与进度追踪功能
  • 实现集中控制的命令模式
  • 管理实时更新与后台操作
  • 希望避免Redux/Zustand带来的额外开销
  • 构建视频播放器、编辑器或多步骤流程类应用
  • 需要通过refs实现精准的性能控制

Core Patterns

核心模式

  1. Multi-Stage Loading States - Track progress through complex operations
  2. Command Pattern - Centralized playback/control commands
  3. Ref-Based Optimization - Avoid re-renders for frequently changing values
  4. Memoized Setters - Prevent unnecessary child re-renders
  5. Parallel State Updates - Batch related changes together
  1. 多阶段加载状态 - 追踪复杂操作的执行进度
  2. 命令模式 - 集中式播放/控制命令
  3. 基于Ref的优化 - 避免频繁变化的值触发重渲染
  4. 记忆化设置器 - 防止不必要的子组件重渲染
  5. 并行状态更新 - 批量处理相关变更

Implementation

实现方案

Pattern 1: Multi-Stage Loading with Progress

模式1:带进度追踪的多阶段加载

typescript
'use client';

import { useState, useRef } from 'react';
import { AbortManager } from '@/lib/promise-utils';

type PageState = 'IDLE' | 'ANALYZING_NEW' | 'LOADING_CACHED' | 'ERROR';
type LoadingStage = 'fetching' | 'understanding' | 'generating' | 'processing' | null;

export function ComplexPage() {
  // Page state machine
  const [pageState, setPageState] = useState<PageState>('IDLE');
  const [loadingStage, setLoadingStage] = useState<LoadingStage>(null);
  const [error, setError] = useState<string>('');

  // Progress tracking
  const [generationStartTime, setGenerationStartTime] = useState<number | null>(null);
  const [processingStartTime, setProcessingStartTime] = useState<number | null>(null);

  // Cleanup manager
  const abortManager = useRef(new AbortManager());

  const handleAnalyze = async () => {
    try {
      // Stage 1: Fetching
      setPageState('ANALYZING_NEW');
      setLoadingStage('fetching');

      const controller1 = abortManager.current.createController('fetch', 30000);
      const data = await fetch('/api/data', { signal: controller1.signal })
        .then(r => r.json());

      // Stage 2: Understanding
      setLoadingStage('understanding');

      // Stage 3: Generating
      setLoadingStage('generating');
      setGenerationStartTime(Date.now());

      const controller2 = abortManager.current.createController('generate', 60000);
      const analysis = await fetch('/api/analyze', {
        signal: controller2.signal,
        method: 'POST',
        body: JSON.stringify(data)
      }).then(r => r.json());

      // Stage 4: Processing
      setLoadingStage('processing');
      setProcessingStartTime(Date.now());

      // Process results...

      setPageState('IDLE');
      setLoadingStage(null);
      setGenerationStartTime(null);

    } catch (error) {
      setPageState('ERROR');
      setError(error.message);
    }
  };

  // Cleanup on unmount
  useEffect(() => {
    return () => abortManager.current.cleanup();
  }, []);

  return (
    <div>
      {loadingStage && (
        <LoadingIndicator
          stage={loadingStage}
          elapsedTime={generationStartTime ? Date.now() - generationStartTime : 0}
        />
      )}
    </div>
  );
}
typescript
'use client';

import { useState, useRef } from 'react';
import { AbortManager } from '@/lib/promise-utils';

type PageState = 'IDLE' | 'ANALYZING_NEW' | 'LOADING_CACHED' | 'ERROR';
type LoadingStage = 'fetching' | 'understanding' | 'generating' | 'processing' | null;

export function ComplexPage() {
  // Page state machine
  const [pageState, setPageState] = useState<PageState>('IDLE');
  const [loadingStage, setLoadingStage] = useState<LoadingStage>(null);
  const [error, setError] = useState<string>('');

  // Progress tracking
  const [generationStartTime, setGenerationStartTime] = useState<number | null>(null);
  const [processingStartTime, setProcessingStartTime] = useState<number | null>(null);

  // Cleanup manager
  const abortManager = useRef(new AbortManager());

  const handleAnalyze = async () => {
    try {
      // Stage 1: Fetching
      setPageState('ANALYZING_NEW');
      setLoadingStage('fetching');

      const controller1 = abortManager.current.createController('fetch', 30000);
      const data = await fetch('/api/data', { signal: controller1.signal })
        .then(r => r.json());

      // Stage 2: Understanding
      setLoadingStage('understanding');

      // Stage 3: Generating
      setLoadingStage('generating');
      setGenerationStartTime(Date.now());

      const controller2 = abortManager.current.createController('generate', 60000);
      const analysis = await fetch('/api/analyze', {
        signal: controller2.signal,
        method: 'POST',
        body: JSON.stringify(data)
      }).then(r => r.json());

      // Stage 4: Processing
      setLoadingStage('processing');
      setProcessingStartTime(Date.now());

      // Process results...

      setPageState('IDLE');
      setLoadingStage(null);
      setGenerationStartTime(null);

    } catch (error) {
      setPageState('ERROR');
      setError(error.message);
    }
  };

  // Cleanup on unmount
  useEffect(() => {
    return () => abortManager.current.cleanup();
  }, []);

  return (
    <div>
      {loadingStage && (
        <LoadingIndicator
          stage={loadingStage}
          elapsedTime={generationStartTime ? Date.now() - generationStartTime : 0}
        />
      )}
    </div>
  );
}

Pattern 2: Command Pattern for Centralized Control

模式2:用于集中控制的命令模式

typescript
// Define command types
export type PlaybackCommandType = 'SEEK' | 'PLAY_TOPIC' | 'PLAY_SEGMENT' | 'PLAY' | 'PAUSE' | 'PLAY_ALL';

export interface PlaybackCommand {
  type: PlaybackCommandType;
  time?: number;
  topic?: Topic;
  segment?: Segment;
  autoPlay?: boolean;
}

// Parent component
export function VideoAnalysisPage() {
  const [playbackCommand, setPlaybackCommand] = useState<PlaybackCommand | null>(null);

  const handleTopicClick = (topic: Topic) => {
    setPlaybackCommand({
      type: 'PLAY_TOPIC',
      topic,
      autoPlay: true
    });
  };

  const handleSeek = (time: number) => {
    setPlaybackCommand({
      type: 'SEEK',
      time
    });
  };

  return (
    <div>
      <VideoPlayer
        command={playbackCommand}
        onCommandExecuted={() => setPlaybackCommand(null)}
      />

      <TopicsList
        topics={topics}
        onTopicClick={handleTopicClick}
      />
    </div>
  );
}

// Child component
export function VideoPlayer({
  command,
  onCommandExecuted
}: {
  command: PlaybackCommand | null;
  onCommandExecuted: () => void;
}) {
  const playerRef = useRef<YouTubePlayer>(null);

  useEffect(() => {
    if (!command || !playerRef.current) return;

    switch (command.type) {
      case 'SEEK':
        playerRef.current.seekTo(command.time!);
        break;

      case 'PLAY_TOPIC':
        playerRef.current.seekTo(command.topic!.startTime);
        if (command.autoPlay) {
          playerRef.current.playVideo();
        }
        break;

      case 'PLAY':
        playerRef.current.playVideo();
        break;

      case 'PAUSE':
        playerRef.current.pauseVideo();
        break;
    }

    onCommandExecuted();
  }, [command]);

  return <div ref={playerRef} />;
}
typescript
// Define command types
export type PlaybackCommandType = 'SEEK' | 'PLAY_TOPIC' | 'PLAY_SEGMENT' | 'PLAY' | 'PAUSE' | 'PLAY_ALL';

export interface PlaybackCommand {
  type: PlaybackCommandType;
  time?: number;
  topic?: Topic;
  segment?: Segment;
  autoPlay?: boolean;
}

// Parent component
export function VideoAnalysisPage() {
  const [playbackCommand, setPlaybackCommand] = useState<PlaybackCommand | null>(null);

  const handleTopicClick = (topic: Topic) => {
    setPlaybackCommand({
      type: 'PLAY_TOPIC',
      topic,
      autoPlay: true
    });
  };

  const handleSeek = (time: number) => {
    setPlaybackCommand({
      type: 'SEEK',
      time
    });
  };

  return (
    <div>
      <VideoPlayer
        command={playbackCommand}
        onCommandExecuted={() => setPlaybackCommand(null)}
      />

      <TopicsList
        topics={topics}
        onTopicClick={handleTopicClick}
      />
    </div>
  );
}

// Child component
export function VideoPlayer({
  command,
  onCommandExecuted
}: {
  command: PlaybackCommand | null;
  onCommandExecuted: () => void;
}) {
  const playerRef = useRef<YouTubePlayer>(null);

  useEffect(() => {
    if (!command || !playerRef.current) return;

    switch (command.type) {
      case 'SEEK':
        playerRef.current.seekTo(command.time!);
        break;

      case 'PLAY_TOPIC':
        playerRef.current.seekTo(command.topic!.startTime);
        if (command.autoPlay) {
          playerRef.current.playVideo();
        }
        break;

      case 'PLAY':
        playerRef.current.playVideo();
        break;

      case 'PAUSE':
        playerRef.current.pauseVideo();
        break;
    }

    onCommandExecuted();
  }, [command]);

  return <div ref={playerRef} />;
}

Pattern 3: Refs for Performance-Critical State

模式3:针对性能关键状态的Refs用法

typescript
export function HighPerformanceComponent() {
  // Use state for UI updates
  const [selectedTheme, setSelectedTheme] = useState<string | null>(null);

  // Use refs for frequently changing values that don't need re-renders
  const selectedThemeRef = useRef<string | null>(null);
  const nextRequestIdRef = useRef(0);
  const activeRequestIdRef = useRef<number | null>(null);
  const pendingRequestsRef = useRef(new Map<string, number>());

  const handleThemeChange = async (theme: string) => {
    // Generate unique request ID
    const requestId = nextRequestIdRef.current++;

    // Cancel previous request for this theme
    const existingRequestId = pendingRequestsRef.current.get(theme);
    if (existingRequestId !== undefined && existingRequestId === activeRequestIdRef.current) {
      return; // Request already in progress
    }

    // Store request ID
    pendingRequestsRef.current.set(theme, requestId);
    activeRequestIdRef.current = requestId;
    selectedThemeRef.current = theme;

    // Update UI
    setSelectedTheme(theme);

    // Fetch data
    const data = await fetchThemeData(theme);

    // Check if this request is still relevant
    if (activeRequestIdRef.current === requestId) {
      // Process data...
    }
  };

  return <div>...</div>;
}
typescript
export function HighPerformanceComponent() {
  // Use state for UI updates
  const [selectedTheme, setSelectedTheme] = useState<string | null>(null);

  // Use refs for frequently changing values that don't need re-renders
  const selectedThemeRef = useRef<string | null>(null);
  const nextRequestIdRef = useRef(0);
  const activeRequestIdRef = useRef<number | null>(null);
  const pendingRequestsRef = useRef(new Map<string, number>());

  const handleThemeChange = async (theme: string) => {
    // Generate unique request ID
    const requestId = nextRequestIdRef.current++;

    // Cancel previous request for this theme
    const existingRequestId = pendingRequestsRef.current.get(theme);
    if (existingRequestId !== undefined && existingRequestId === activeRequestIdRef.current) {
      return; // Request already in progress
    }

    // Store request ID
    pendingRequestsRef.current.set(theme, requestId);
    activeRequestIdRef.current = requestId;
    selectedThemeRef.current = theme;

    // Update UI
    setSelectedTheme(theme);

    // Fetch data
    const data = await fetchThemeData(theme);

    // Check if this request is still relevant
    if (activeRequestIdRef.current === requestId) {
      // Process data...
    }
  };

  return <div>...</div>;
}

Pattern 4: Memoized Setters for Child Components

模式4:用于子组件的记忆化设置器

typescript
export function ParentWithManyChildren() {
  const [playAllIndex, setPlayAllIndex] = useState(0);
  const [isPlaying, setIsPlaying] = useState(false);

  // Memoize setters to prevent child re-renders
  const memoizedSetPlayAllIndex = useCallback((value: number | ((prev: number) => number)) => {
    setPlayAllIndex(value);
  }, []);

  const memoizedSetIsPlaying = useCallback((value: boolean) => {
    setIsPlaying(value);
  }, []);

  return (
    <>
      {/* Child won't re-render when other state changes */}
      <PlaybackControls
        index={playAllIndex}
        setIndex={memoizedSetPlayAllIndex}
        isPlaying={isPlaying}
        setIsPlaying={memoizedSetIsPlaying}
      />
    </>
  );
}
typescript
export function ParentWithManyChildren() {
  const [playAllIndex, setPlayAllIndex] = useState(0);
  const [isPlaying, setIsPlaying] = useState(false);

  // Memoize setters to prevent child re-renders
  const memoizedSetPlayAllIndex = useCallback((value: number | ((prev: number) => number)) => {
    setPlayAllIndex(value);
  }, []);

  const memoizedSetIsPlaying = useCallback((value: boolean) => {
    setIsPlaying(value);
  }, []);

  return (
    <>
      {/* Child won't re-render when other state changes */}
      <PlaybackControls
        index={playAllIndex}
        setIndex={memoizedSetPlayAllIndex}
        isPlaying={isPlaying}
        setIsPlaying={memoizedSetIsPlaying}
      />
    </>
  );
}

Pattern 5: Parallel State Updates

模式5:并行状态更新

typescript
export function DataFetchingPage() {
  const [data1, setData1] = useState(null);
  const [data2, setData2] = useState(null);
  const [data3, setData3] = useState(null);

  useEffect(() => {
    const fetchAll = async () => {
      // Fetch in parallel
      const [result1, result2, result3] = await Promise.allSettled([
        fetch('/api/data1').then(r => r.json()),
        fetch('/api/data2').then(r => r.json()),
        fetch('/api/data3').then(r => r.json())
      ]);

      // Batch state updates to trigger single re-render
      React.startTransition(() => {
        if (result1.status === 'fulfilled') setData1(result1.value);
        if (result2.status === 'fulfilled') setData2(result2.value);
        if (result3.status === 'fulfilled') setData3(result3.value);
      });
    };

    fetchAll();
  }, []);

  return <div>...</div>;
}
typescript
export function DataFetchingPage() {
  const [data1, setData1] = useState(null);
  const [data2, setData2] = useState(null);
  const [data3, setData3] = useState(null);

  useEffect(() => {
    const fetchAll = async () => {
      // Fetch in parallel
      const [result1, result2, result3] = await Promise.allSettled([
        fetch('/api/data1').then(r => r.json()),
        fetch('/api/data2').then(r => r.json()),
        fetch('/api/data3').then(r => r.json())
      ]);

      // Batch state updates to trigger single re-render
      React.startTransition(() => {
        if (result1.status === 'fulfilled') setData1(result1.value);
        if (result2.status === 'fulfilled') setData2(result2.value);
        if (result3.status === 'fulfilled') setData3(result3.value);
      });
    };

    fetchAll();
  }, []);

  return <div>...</div>;
}

Pattern 6: Custom Hooks for Complex Logic

模式6:用于复杂逻辑的自定义Hooks

typescript
// Custom hook for elapsed time
export function useElapsedTimer(startTime: number | null) {
  const [elapsedTime, setElapsedTime] = useState(0);

  useEffect(() => {
    if (!startTime) {
      setElapsedTime(0);
      return;
    }

    const interval = setInterval(() => {
      setElapsedTime(Date.now() - startTime);
    }, 1000);

    return () => clearInterval(interval);
  }, [startTime]);

  return elapsedTime;
}

// Usage
const generationStartTime = useState<number | null>(null);
const elapsedTime = useElapsedTimer(generationStartTime);

console.log(`Generating for ${Math.floor(elapsedTime / 1000)}s`);
typescript
// Custom hook for elapsed time
export function useElapsedTimer(startTime: number | null) {
  const [elapsedTime, setElapsedTime] = useState(0);

  useEffect(() => {
    if (!startTime) {
      setElapsedTime(0);
      return;
    }

    const interval = setInterval(() => {
      setElapsedTime(Date.now() - startTime);
    }, 1000);

    return () => clearInterval(interval);
  }, [startTime]);

  return elapsedTime;
}

// Usage
const generationStartTime = useState<number | null>(null);
const elapsedTime = useElapsedTimer(generationStartTime);

console.log(`Generating for ${Math.floor(elapsedTime / 1000)}s`);

Pattern 7: Theme-Based Dynamic Content

模式7:基于主题的动态内容

typescript
export function ThemeBasedContent() {
  const [baseTopics, setBaseTopics] = useState<Topic[]>([]);
  const [selectedTheme, setSelectedTheme] = useState<string | null>(null);
  const [themeTopicsMap, setThemeTopicsMap] = useState<Record<string, Topic[]>>({});
  const [usedTopicKeys, setUsedTopicKeys] = useState<Set<string>>(new Set());

  // Display topics based on selected theme
  const displayedTopics = selectedTheme
    ? (themeTopicsMap[selectedTheme] || [])
    : baseTopics;

  const handleThemeSelect = async (theme: string) => {
    setSelectedTheme(theme);

    // Check cache first
    if (themeTopicsMap[theme]) {
      return; // Already loaded
    }

    // Fetch theme-specific topics
    const newTopics = await fetch('/api/topics', {
      method: 'POST',
      body: JSON.stringify({
        theme,
        excludeKeys: Array.from(usedTopicKeys)
      })
    }).then(r => r.json());

    // Update cache and used keys
    setThemeTopicsMap(prev => ({
      ...prev,
      [theme]: newTopics
    }));

    setUsedTopicKeys(prev => {
      const newSet = new Set(prev);
      newTopics.forEach(t => newSet.add(t.key));
      return newSet;
    });
  };

  return (
    <div>
      <ThemeSelector onSelect={handleThemeSelect} />
      <TopicsList topics={displayedTopics} />
    </div>
  );
}
typescript
export function ThemeBasedContent() {
  const [baseTopics, setBaseTopics] = useState<Topic[]>([]);
  const [selectedTheme, setSelectedTheme] = useState<string | null>(null);
  const [themeTopicsMap, setThemeTopicsMap] = useState<Record<string, Topic[]>>({});
  const [usedTopicKeys, setUsedTopicKeys] = useState<Set<string>>(new Set());

  // Display topics based on selected theme
  const displayedTopics = selectedTheme
    ? (themeTopicsMap[selectedTheme] || [])
    : baseTopics;

  const handleThemeSelect = async (theme: string) => {
    setSelectedTheme(theme);

    // Check cache first
    if (themeTopicsMap[theme]) {
      return; // Already loaded
    }

    // Fetch theme-specific topics
    const newTopics = await fetch('/api/topics', {
      method: 'POST',
      body: JSON.stringify({
        theme,
        excludeKeys: Array.from(usedTopicKeys)
      })
    }).then(r => r.json());

    // Update cache and used keys
    setThemeTopicsMap(prev => ({
      ...prev,
      [theme]: newTopics
    }));

    setUsedTopicKeys(prev => {
      const newSet = new Set(prev);
      newTopics.forEach(t => newSet.add(t.key));
      return newSet;
    });
  };

  return (
    <div>
      <ThemeSelector onSelect={handleThemeSelect} />
      <TopicsList topics={displayedTopics} />
    </div>
  );
}

Best Practices

最佳实践

  1. Use refs for non-UI state - Don't trigger re-renders unnecessarily
  2. Batch related state updates - Use startTransition or update together
  3. Memoize callbacks - Prevent child component re-renders
  4. Clean up on unmount - Always cleanup timers, subscriptions, AbortControllers
  5. Use state machines - Explicit states prevent invalid state combinations
  6. Separate concerns - Loading state, data state, UI state
  7. Cache when possible - Avoid re-fetching with Map/Set caches
  1. 将refs用于非UI状态 - 避免不必要的重渲染
  2. 批量处理相关状态更新 - 使用startTransition或一次性更新
  3. 记忆化回调函数 - 防止子组件重渲染
  4. 组件卸载时清理资源 - 始终清理定时器、订阅和AbortControllers
  5. 使用状态机 - 明确的状态可避免无效的状态组合
  6. 分离关注点 - 区分加载状态、数据状态与UI状态
  7. 尽可能使用缓存 - 通过Map/Set缓存避免重复请求

Common Pitfalls

常见陷阱

  1. Too many useState calls - Group related state into objects
  2. Not cleaning up - Memory leaks from timers/subscriptions
  3. Passing non-memoized callbacks - Causes unnecessary re-renders
  4. Using state for everything - Use refs for non-UI values
  5. Not batching updates - Multiple state updates = multiple renders
  6. Forgetting dependencies - useEffect/useCallback need correct deps
  7. Mutating state - Always create new objects/arrays
  1. 过多useState调用 - 将相关状态分组为对象
  2. 未清理资源 - 定时器/订阅导致内存泄漏
  3. 传递非记忆化的回调 - 引发不必要的重渲染
  4. 所有数据都用state存储 - 非UI值使用refs
  5. 未批量更新状态 - 多次状态更新会触发多次重渲染
  6. 遗漏依赖项 - useEffect/useCallback需要正确的依赖数组
  7. 直接修改状态 - 始终创建新的对象/数组

Performance Optimization

性能优化

typescript
// ❌ Bad: Multiple re-renders
function Component() {
  const [a, setA] = useState(0);
  const [b, setB] = useState(0);
  const [c, setC] = useState(0);

  const update = () => {
    setA(1); // Re-render 1
    setB(2); // Re-render 2
    setC(3); // Re-render 3
  };
}

// ✅ Good: Single re-render
function Component() {
  const [state, setState] = useState({ a: 0, b: 0, c: 0 });

  const update = () => {
    setState({ a: 1, b: 2, c: 3 }); // Re-render 1
  };
}

// ✅ Better: Use startTransition for non-urgent updates
function Component() {
  const [a, setA] = useState(0);
  const [b, setB] = useState(0);
  const [c, setC] = useState(0);

  const update = () => {
    startTransition(() => {
      setA(1);
      setB(2);
      setC(3);
    });
  };
}
typescript
// ❌ Bad: Multiple re-renders
function Component() {
  const [a, setA] = useState(0);
  const [b, setB] = useState(0);
  const [c, setC] = useState(0);

  const update = () => {
    setA(1); // Re-render 1
    setB(2); // Re-render 2
    setC(3); // Re-render 3
  };
}

// ✅ Good: Single re-render
function Component() {
  const [state, setState] = useState({ a: 0, b: 0, c: 0 });

  const update = () => {
    setState({ a: 1, b: 2, c: 3 }); // Re-render 1
  };
}

// ✅ Better: Use startTransition for non-urgent updates
function Component() {
  const [a, setA] = useState(0);
  const [b, setB] = useState(0);
  const [c, setC] = useState(0);

  const update = () => {
    startTransition(() => {
      setA(1);
      setB(2);
      setC(3);
    });
  };
}

Testing

测试

typescript
import { renderHook, act } from '@testing/library/react';

test('useElapsedTimer increments over time', () => {
  jest.useFakeTimers();

  const { result } = renderHook(() => useElapsedTimer(Date.now()));

  expect(result.current).toBe(0);

  act(() => {
    jest.advanceTimersByTime(5000);
  });

  expect(result.current).toBeGreaterThanOrEqual(5000);
});
typescript
import { renderHook, act } from '@testing/library/react';

test('useElapsedTimer increments over time', () => {
  jest.useFakeTimers();

  const { result } = renderHook(() => useElapsedTimer(Date.now()));

  expect(result.current).toBe(0);

  act(() => {
    jest.advanceTimersByTime(5000);
  });

  expect(result.current).toBeGreaterThanOrEqual(5000);
});

Next Steps

后续步骤

  1. Extract common patterns into custom hooks
  2. Add state persistence with localStorage
  3. Implement undo/redo with state history
  4. Add state debugging with DevTools
  5. Create state machines with XState if needed
  6. Profile render performance with React DevTools
  1. 将通用模式提取为自定义Hooks
  2. 结合localStorage实现状态持久化
  3. 基于状态历史实现撤销/重做功能
  4. 通过DevTools添加状态调试功能
  5. 必要时使用XState实现状态机
  6. 借助React DevTools分析渲染性能

Related Skills

相关技能

  • Resilient Async Operations - Manage async state safely
  • Type-Safe Form Validation - Validate state updates
  • Advanced Text Search - Complex search state management

Built from production state management in TLDW video analysis UI
  • 可靠的异步操作 - 安全管理异步状态
  • 类型安全的表单验证 - 验证状态更新
  • 高级文本搜索 - 复杂搜索状态管理

基于TLDW视频分析UI中的生产级状态管理方案构建",