DhiWise Logo

Design Converter

  • Technologies
  • Resource
  • Pricing

Education

Creating Dynamic React Tables: Leveraging React Query's Power

Last updated on Nov 2, 2023

15 mins read

Brief Overview of React

React is a JavaScript library that has changed the way we approach web development. Because of its component-based architecture, developers can create sophisticated user interfaces out of smaller, reusable elements. This approach makes it easier to manage the state of your application, leading to more maintainable code and a better user experience.

When we talk about components in React, we often refer to examples like a table component, which can be reused in various parts of a React application.

What are Dynamic Tables in React?

Dynamic tables in React are table components that can change based on the data they are given. Instead of hardcoding the rows and columns of a table, a dynamic React table generates its rows and columns based on the provided data. This allows the table to update when the data changes, providing a much more flexible and powerful user interface.

For instance, a dynamic React table might be used to display user data fetched from a remote API. The table columns might represent user attributes like name, email, and role, while each table row represents a different user. If the remote data changes (e.g., a new user is added), the React table can automatically update to reflect these changes.

Introduction to React Query

img

React Query is a robust library that allows you to fetch, cache, and update server data in your React apps. It provides a set of hooks that you can use to fetch remote data and keep your local data state in sync with the server. This is incredibly useful when working with dynamic React tables, as it allows you to easily fetch new data, refresh existing data, and even implement features like server-side pagination and sorting.

Key Features of React Query

Data Fetching:

React Query simplifies data fetching by providing hooks like useQuery and useMutation that handle API requests and responses with minimal boilerplate code.

img

Caching:

The library includes built-in caching mechanisms that store fetched data in memory, reducing redundant API calls and improving performance.

Automatic Data Refetching:

React Query automatically refetches data based on specified intervals or when specific events occur, keeping the data up-to-date without manual intervention.

img

Parallel Data Fetching:

It allows parallel fetching of multiple resources, optimizing data loading and reducing page load times.

img

Mutation and Optimistic Updates:

React Query supports mutations with optimistic updates, enabling smooth and instantaneous UI updates even before the server responds.

img

One of the most important advantages of React Query is its caching capabilities. When you fetch data with React Query, it automatically caches the data for you. This means that if you need to fetch the same data again (e.g., when a user navigates to a different page and then back), React Query can return the cached data instead of making a new API request. This can result in significant performance gains, particularly for bigger datasets.

React Query also provides out-of-the-box support for features like background updates and stale data refetching. This means that you can configure your React tables to automatically refresh their data at regular intervals, or whenever the user focuses their browser window.

In comparison with other data-fetching libraries, React Query stands out for its flexibility and performance optimizations. It provides all the state management tools you need to work with remote data, while also maintaining great performance even when dealing with large datasets.

Setting Up the Development Environment

Installing Node.js and npm

Before we dive into creating our dynamic React table, we need to ensure that we have the proper development environment set up. The first step in this process is to install Node.js and npm (Node Package Manager).

With the help of the JavaScript runtime Node.js, we can run JavaScript scripts without the need for a web browser. It is essential for developing React applications, as it provides the environment where our code will be executed during development.

npm, on the other hand, is a package manager for JavaScript. It allows us to install and manage the libraries that our React application will depend on, such as React Query. For example, to fetch remote data for our React table, we'll use the React Query library, which we can easily install with npm.

To install Node.js and npm, you can download the latest stable versions from the official Node.js website. After the installation, you can verify that everything was installed correctly by opening a terminal or command prompt and running the following commands:

1 node --version 2 3 npm --version 4

These commands should display the installed versions of Node.js and npm, respectively.

Creating a New React Application

Now that we have Node.js and npm installed, we can proceed to create a new React application. For this, we'll use the create-react-app tool, which is a command-line utility that sets up a new React application with a solid default configuration.

To create a new React application, open a terminal or command prompt, navigate to the directory where you want to create your application, and run the following command:

1 npx create-react-app react-table-example 2

This command will create a new directory named react-table-example, and it will set up a new React application inside this directory. Once the command completes, you can navigate into your new application's directory with the command cd react-table-example.

Inside the react-table-example directory, you'll find a standard set of files and directories that make up a React application. The src directory is where you'll spend most of your time, as it contains the JavaScript files where your React components, including your React table components, will be defined.

Installing and Setting Up React Query

With our React application created, we can now install React Query. As mentioned earlier, React Query is a powerful library for fetching, caching, and updating remote data in React applications, and it will be a key part of our dynamic React table.

To install React Query, we can use npm. In your terminal or command prompt, make sure you're in the react-table-example directory, and run the following command:

1 npm install react-query 2

This command will add React Query to our application's dependencies, and it will be available for us to import and use in our React components.

To set up React Query, we'll need to wrap our application in a QueryClientProvider component, which is provided by React Query. This component requires a QueryClient instance, which we can create using the new QueryClient() constructor. The QueryClient is what enables much of React Query's functionality, including its caching and automatic background updates.

Setting up React Query might look something like this:

1 import React from 'react'; 2 import { QueryClient, QueryClientProvider } from 'react-query'; 3 const queryClient = new QueryClient(); 4 function App() { 5 return ( 6 <QueryClientProvider client={queryClient}> 7 {/* Your React table components will go here */} 8 </QueryClientProvider> 9 ); 10 } 11 export default App; 12

With this setup, we're now ready to start building our dynamic React table with React Query!

Making the React Table Dynamic

Sorting Data

One of the most common features of a dynamic React table is the ability to sort data. Users often need to sort table data based on different columns to better understand and analyze the data. Implementing sorting in a React table involves manipulating the data array that the table displays.

React provides a hook called useMemo that can be very useful for this. The useMemo hook allows you to memoize expensive functions, meaning that it remembers the result of a function and only re-computes it when one of its dependencies changes. This can significantly improve performance, especially when working with large data arrays.

Here's an example of how you might use useMemo to implement sorting in a React table:

1 import React, { useMemo, useState } from 'react'; 2 function Table({ data }) { 3 const [sortConfig, setSortConfig] = useState(null); 4 const sortedData = useMemo(() => { 5 let sortableData = [...data]; 6 if (sortConfig !== null) { 7 sortableData.sort((a, b) => { 8 if (a[sortConfig.key] < b[sortConfig.key]) { 9 return sortConfig.direction === 'ascending' ? -1 : 1; 10 } 11 if (a[sortConfig.key] > b[sortConfig.key]) { 12 return sortConfig.direction === 'ascending' ? 1 : -1; 13 } 14 return 0; 15 }); 16 } 17 return sortableData; 18 }, [data, sortConfig]); 19 // ... 20 return (<table> //your table code </table>); 21 } 22

In this example, we use useState to keep track of the current sorting configuration, which includes the key to sort by and the direction of the sort (either 'ascending' or 'descending'). We then use useMemo to create a sorted copy of the data array whenever the data or the sort configuration changes.

Filtering Data

Another common feature of a dynamic React table is filtering. Similar to sorting, filtering allows users to manipulate the view of the data to suit their needs.

To implement filtering in a React table, we can use the useState and useEffect hooks. The useState hook can be used to keep track of the current filter configuration, and the useEffect hook can be used to update the displayed data whenever the filter configuration changes.

Here's an example:

1 import React, { useState, useEffect } from "react"; 2 function Table({ data }) { 3 const [filterConfig, setFilterConfig] = useState(null); 4 const [filteredData, setFilteredData] = useState(data); 5 useEffect(() => { 6 let newData = [...data]; 7 if (filterConfig !== null) { 8 newData = newData.filter((row) => 9 row[filterConfig.key].includes(filterConfig.value) 10 ); 11 } 12 setFilteredData(newData); 13 }, [data, filterConfig]); 14 return (<table> //your table code </table>); 15 } 16

In this example, we use useState to keep track of the current filter configuration, which includes the key to filter by and the value to filter with. We then use useEffect to create a filtered copy of the data array whenever the data or the filter configuration changes.

Pagination

It is a technique used to handle large sets of data by dividing the data into multiple pages. Each page contains a certain number of rows, and users can navigate between pages as needed. Pagination can significantly improve performance and usability when dealing with large data sets.

React Query provides a usePaginatedQuery hook that we can use to fetch data in pages. The usePaginatedQuery hook works similarly to the useQuery hook, but it provides additional information about the pagination state, such as the current page and the total number of pages.

Here's an example of how you might use the usePaginatedQuery hook to implement pagination in a React table:

1 import React from 'react'; 2 import { usePaginatedQuery } from 'react-query'; 3 async function fetchData(pageNumber) { 4 const response = await fetch(`https://api.example.com/data?page=${pageNumber}`); 5 if (!response.ok) { 6 throw new Error('Network response was not ok'); 7 } 8 return response.json(); 9 } 10 function Table() { 11 const [pageNumber, setPageNumber] = useState(1); 12 const { resolvedData, latestData, status } = usePaginatedQuery(['data', pageNumber], fetchData); 13 // ... 14 return ( 15 <div> 16 {/* Render the React table with resolvedData */} 17 <button 18 onClick={() => setPageNumber((old) => Math.max(old - 1, 1))} 19 disabled={pageNumber === 1} 20 > 21 Previous Page 22 </button> 23 <button 24 onClick={() => { 25 if (!latestData?.nextPage) { 26 return; 27 } 28 setPageNumber((old) => old + 1); 29 }} 30 disabled={!latestData?.nextPage} 31 > 32 Next Page 33 </button> 34 </div> 35 ); 36 } 37 export default Table; 38

In this example, we use useState to keep track of the current page number. We then pass this page number to the fetchData function, which includes it in the API request to fetch the corresponding page of data.

The usePaginatedQuery hook returns an object with several properties. We're using resolvedData to get the data for the current page, latestData to determine whether there's a next page, and status to handle loading and error states.

Finally, we render two buttons for navigating to the previous and next pages. We use the setPageNumber function to update the current page number when a button is clicked. With sorting, filtering, and pagination implemented, our React table is now truly dynamic.

Enhancing the React Table with Server-side Operations

Server-side Sorting and Filtering

While client-side sorting and filtering are suitable for smaller datasets, they can become inefficient for larger datasets. This is because the entire dataset needs to be loaded into the client's memory, which can lead to performance issues.

Server-side operations can solve this problem. Instead of sending the entire dataset to the client, the server only sends the data that is currently needed. The server also takes care of sorting and filtering the data based on parameters sent by the client.

To implement server-side sorting and filtering with React Query, we need to modify our fetchData function to include parameters for sorting and filtering. Here's an example:

1 async function fetchData({ queryKey }) { 2 3 const [_key, { pageNumber, sortConfig, filterConfig }] = queryKey; 4 5 const response = await fetch(`https://api.example.com/data?page=${pageNumber}&sort=${sortConfig.key}&direction=${sortConfig.direction}&filter=${filterConfig.key}&value=${filterConfig.value}`); 6 7 if (!response.ok) { 8 9 throw new Error('Network response was not ok'); 10 11 } 12 13 return response.json(); 14 15 } 16

In this example, we use the queryKey parameter of the fetchData function to get the current page number, sort configuration, and filter configuration. We then include these values in the API request.

When we call the useQuery or usePaginatedQuery hook, we need to pass an array as the query key, with the second element of the array being an object that contains the current page number, sort configuration, and filter configuration.

Server-side Pagination

Server-side pagination works similarly to client-side pagination, but instead of handling the pagination logic on the client-side, the server takes care of it. This can be more efficient for large datasets, as it reduces the amount of data that needs to be sent to the client.

React Query's usePaginatedQuery hook makes it easy to implement server-side pagination. We just need to include the current page number in the API request, and the server should return the data for that page.

Here's an example of how you might implement server-side pagination in a React table:

1 import React, { useState } from 'react'; 2 import { usePaginatedQuery } from 'react-query'; 3 async function fetchData({ queryKey }) { 4 const [_key, pageNumber] = queryKey; 5 const response = await fetch(`https://api.example.com/data?page=${pageNumber}`); 6 if (!response.ok) { 7 throw new Error('Network response was not ok'); 8 } 9 return response.json(); 10 } 11 function Table() { 12 const [pageNumber, setPageNumber] = useState(1); 13 const { resolvedData, latestData, status } = usePaginatedQuery(['data', pageNumber], fetchData); 14 // ... 15 return ( 16 <div> 17 {/* Render the React table with resolvedData */} 18 <button 19 onClick={() => setPageNumber((old) => Math.max(old - 1, 1))} 20 disabled={pageNumber === 1} 21 > 22 Previous Page 23 </button> 24 <button 25 onClick={() => setPageNumber((old) => old + 1)} 26 disabled={!latestData?.nextPage} 27 > 28 Next Page 29 </button> 30 </div> 31 ); 32 } 33 export default Table; 34

In this example, the fetchData function includes the current page number in the API request, and the server is expected to return the data for that page. The usePaginatedQuery hook then provides us with the data for the current page, as well as information about the pagination state.

Introducing WiseGPT for Effortless API Integration

img

While React Query simplifies data handling in React applications, it still requires manual implementation of API request and response handling. WiseGPT takes this simplification to the next level by automating the entire process of API code generation in React projects.

WiseGPT is a revolutionary plugin that allows developers to generate code for APIs directly into their React projects. With WiseGPT, you can create an API collection and let the plugin handle everything, from making API requests to parsing responses and managing errors.

Key Features of WiseGPT

  • Promptless API Integration: WiseGPT eliminates the need for writing prompts or manually configuring API calls. You simply provide an API collection, and WiseGPT takes care of the rest.
  • Mirrors Coding Style: The generated API code from WiseGPT seamlessly integrates with your existing coding style and project structure.
  • Auto-Created Models and Functions: WiseGPT automatically creates models and functions based on the provided API collection, saving valuable development time.
  • No Output Size Limit: Unlike other code generators, WiseGPT does not limit the output size, ensuring that your entire API collection is fully integrated into your React project.

Conclusion

In this blog, we've covered a lot of ground on the topic of building dynamic React tables using React Query. We started with the basics of setting up a React development environment and creating a basic table component. We then dove into fetching remote data using React Query, which forms the backbone of our dynamic React table.

We explored how to make our React table dynamic by implementing sorting and filtering functionality. We discussed the importance of React's useMemo hook for optimizing performance during sorting, and how useState and useEffect can be used to implement dynamic filtering. We also covered pagination, an essential feature for handling large datasets, using React Query's usePaginatedQuery hook.

We then took our React table to the next level by implementing server-side operations. We learned how to modify our React Query fetch function to include parameters for sorting and filtering, and how to implement server-side pagination. These techniques allow us to handle larger datasets more efficiently, reducing the amount of data that needs to be loaded into the client's memory and improving performance.

Throughout the blog, we emphasized the importance of maintaining great performance when rendering thousands of rows in a React table. We discussed techniques such as memoization and server-side operations, which can significantly improve performance for large datasets.

Mastering these skills is crucial for modern web development. Dynamic tables are a common requirement in many web applications, and libraries like React and React Query provide powerful tools to build these tables efficiently and effectively.

Short on time? Speed things up with DhiWise!

Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!

You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.

Sign up to DhiWise for free

Frequently asked questions

How does React Query differ from other data fetching libraries in React?

down arrow

Can you explain how React Query's caching strategies work, and how can they be fine-tuned for advanced scenarios?

down arrow

In complex applications with multiple API endpoints, how can React Query efficiently manage and synchronize data across various components and views?

down arrow

What are some best practices for handling pagination in React Query when dealing with large datasets?

down arrow

How can we extend React Query to work with custom authentication and authorization mechanisms in production applications?

down arrow

In scenarios where real-time data updates are essential, how can React Query be integrated with technologies like WebSockets or Server-Sent Events (SSE)?

down arrow

When dealing with complex data relationships, how can we optimize data fetching and minimize redundant API calls using React Query?

down arrow

What are some strategies for handling error and loading states gracefully in advanced React Query setups?

down arrow

Are there any performance benchmarks or tools available to profile and optimize React Query's performance in large-scale applications?

down arrow

How can advanced developers integrate React Query with existing state management solutions like Redux or MobX for seamless data flow?

down arrow
Read More