User Data Fetcher with State Management

mediumTypeScript

Lesson

Async State Management in Data Fetching

When building applications that fetch data from APIs, managing the different states of an async operation is crucial for creating a good user experience. Every data fetching operation goes through several possible states: loading, success, error, and sometimes empty data scenarios.

The Four Core States

Modern applications need to handle these states elegantly:

  • Loading State: Indicates an operation is in progress
  • Success State: Data has been fetched and is ready to display
  • Error State: Something went wrong and needs user attention
  • Empty State: The operation succeeded but returned no data

State Transitions and Data Persistence

One important consideration is how state transitions affect existing data. When an error occurs after a successful data fetch, you typically want to preserve the existing data while showing the error. This allows users to still see previous content while being informed about the failure.

Error Recovery Patterns

Retry functionality is essential for robust data fetching. Users should be able to easily recover from temporary network issues or server problems. The key is storing enough information about the failed operation to repeat it exactly, including any parameters that were originally passed.

Implementation Strategy

Effective state management for data fetching typically involves:

  • Tracking multiple state flags simultaneously (loading + error + data)
  • Using try-catch-finally blocks to ensure state cleanup
  • Storing failed operation details for retry functionality
  • Providing clear methods to query current state

This pattern is fundamental in modern web development and forms the basis for more advanced state management solutions.

Example
1class SimpleDataFetcher { 2 private loading = false; 3 private data: any[] | null = null; 4 private error: string | null = null; 5 6 async fetchData() { 7 this.loading = true; 8 this.error = null; 9 10 try { 11 const response = await api.getData(); 12 this.data = response; 13 } catch (err) { 14 this.error = 'Failed to load data'; 15 // Note: we don't clear existing data on error 16 } finally { 17 this.loading = false; // Always cleanup loading state 18 } 19 } 20 21 getState() { 22 return { loading: this.loading, data: this.data, error: this.error }; 23 } 24}
L5Clear error at start of new request, but preserve existing data
L11On error, keep existing data so user can still see previous content
L13Finally block ensures loading state is always cleaned up

Key Takeaways

  • •Always manage loading, success, error, and empty states separately
  • •Preserve existing data when errors occur to maintain user experience
  • •Use try-catch-finally blocks to ensure proper state cleanup
Loading...