Building a Flexible MatchQueryStatus Component for Handling Async Data in React
The Problem: Managing Async Data States in React Components
When working with APIs in React, managing the various states of asynchronous data—loading, success, error, and empty—can become repetitive and cumbersome. This is especially true when using React Query's useQuery hook in multiple components.
Introduction
In this post, we'll create a flexible and reusable MatchQueryStatus component to handle asynchronous data states in React using React Query. This component streamlines data-loading states and provides flexibility for UI customization.
The Basics of React Query
React Query simplifies server-side data management with features like caching, synchronization, and stale data handling. When using useQuery, you receive a query result object with:
isLoading: true while the data is being fetched.
isError: true if an error occurs.
data: the fetched data once it’s successfully retrieved.
refetch: a function to retry the fetch.
Building the MatchQueryStatus Component
Our MatchQueryStatus component:
Accepts a React Query result and various rendering components or functions
Renders different UI components based on the query's state
Provides flexibility by allowing custom components for loading, error, empty, and success states
The Loader Component
This helper component displays a loading spinner.
Defining the MatchQueryStatusProps Type
This type accepts properties based on different cases:
Case 1: We use the render prop to display data if it’s available and handle errors and loading states with custom components.
Case 2: We define custom components for each state, including Loading, Errored, Empty, and Success.
Type Guard for render Prop
The hasRender function checks if the props include a render prop. This type guard helps us determine how to handle the MatchQueryStatus component’s behavior.
The MatchQueryStatus Component
This component’s main function is to check the query’s state (isLoading, isError, isSuccess, or empty data) and render the appropriate UI based on the props passed. Here’s the full implementation:
Explanation
Loading State: If the query is loading, it checks if a custom Loading component is provided. If not, it defaults to using the Loader component.
Error State: If there’s an error, it uses the Errored component, which can be customized.
Empty State: Checks if the data is empty (i.e., undefined, null, or an empty array) and displays an EmptyCard if so.
Success State: When data is successfully fetched, it renders the Success component with the data.
Usage Example
Here’s how you might use MatchQueryStatus in a React component.
Without render prop
With render prop
Conclusion
The MatchQueryStatus component is a flexible and reusable way to handle the various states of asynchronous data in a React application. By leveraging React Query and customizable props, you can maintain a consistent structure for your API calls and keep your components clean and readable. This approach can significantly enhance the user experience, especially in complex applications where multiple asynchronous calls are made.