In this article, we will build a Task Manager app to understand What is React Query? and How to use React Query useMutation, and React Query useQuery Hooks?
What is React Query?
React Query provides many advantages for caching, managing data fetching, synchronization, and state management of react applications.
Some of the advantages of React Query are
- Data fetching becomes very simple and easy with react query because it does not require complex configurations and a lot of boilerplate codes.
- React query can automatically refetch data with background data synchronization by defining an interval, it makes the app up to date.
- React query handles requests parallelly, we can define the dependent queries that can automatically update when the data they depend on changes.
- It has a built-in error-handling feature that can handle failed requests.
Now, let’s create our task manager app that allows users to view, add, and delete tasks using React Query.
First, create a new React application using Create React App
npx create-react-app react-query-task-manager
cd react-query-task-manager
Install React Query in our project
npm install react-query
React Query Task Manager App
Create a TaskManagerApp.js component file, in this file, we will display all our methods for view, create, update, and delete.
import React, { useState } from 'react';
import { useQuery, useMutation, useQueryClient } from 'react-query';
const fetchTasks = async () => {
const response = await fetch('/api/tasks');
const data = await response.json();
return data;
};
const addTask = async (newTask) => {
const response = await fetch('/api/tasks', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newTask),
});
const data = await response.json();
return data;
};
const updateTask = async (task) => {
const response = await fetch(`/api/tasks/${task.id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(task),
});
const data = await response.json();
return data;
};
const deleteTask = async (taskId) => {
const response = await fetch(`/api/tasks/${taskId}`, {
method: 'DELETE',
});
const data = await response.json();
return data;
};
const TaskManagerApp = () => {
const [taskTitle, setTaskTitle] = useState('');
const queryClient = useQueryClient();
const { data: tasks, isLoading, isError } = useQuery('tasks', fetchTasks);
const addMutation = useMutation(addTask, {
onSuccess: () => {
queryClient.invalidateQueries('tasks');
setTaskTitle('');
},
});
const updateMutation = useMutation(updateTask, {
onSuccess: () => {
queryClient.invalidateQueries('tasks');
},
});
const deleteMutation = useMutation(deleteTask, {
onSuccess: () => {
queryClient.invalidateQueries('tasks');
},
});
const handleSubmit = (e) => {
e.preventDefault();
if (taskTitle.trim() !== '') {
addMutation.mutate({ title: taskTitle });
}
};
const handleUpdate = (task) => {
updateMutation.mutate(task);
};
const handleDelete = (taskId) => {
deleteMutation.mutate(taskId);
};
if (isLoading) return <div>Loading...</div>;
if (isError) return <div>Error fetching tasks</div>;
return (
<div>
<h1>Task Manager App</h1>
<div>
<h2>Add Task</h2>
<form onSubmit={handleSubmit}>
<input
type="text"
value={taskTitle}
onChange={(e) => setTaskTitle(e.target.value)}
/>
<button type="submit" disabled={addMutation.isLoading}>
Add Task
</button>
</form>
</div>
<div>
<h2>Task List</h2>
<ul>
{tasks.map((task) => (
<li key={task.id}>
<input
type="text"
value={task.title}
onChange={(e) =>
handleUpdate({ ...task, title: e.target.value })
}
/>
<button onClick={() => handleDelete(task.id)}>Delete</button>
</li>
))}
</ul>
</div>
</div>
);
};
export default TaskManagerApp;
In the above code, We have defined our TaskManagerApp component which is the main component of our application.
We are using the useState hook to manage our state of title input, to fetch the list of tasks we are using the useQuery hook, this fetches data we are storing in a variable called tasks.
There are isLoading and isError variables, those are for tracking if the data is currently being fetched or if there is some error occurred.
One another important hook we are using is the react query useMutation hook, we are using this to manage mutations like add, update, and delete tasks.
There is one handleSubmit function that is called when the user submits the task title form. It calls the addMutation.mutate function to add a new task using the addTask mutation function in a similar way we also have the handleUpdate function is called when the user updates a task’s title and the handleDelete function is called when the user clicks the delete button.
Now, update our App.js file and import our TaskManagerApp component into it.
import React from 'react';
import ReactDOM from 'react-dom';
import { QueryClient, QueryClientProvider } from 'react-query';
import './index.css';
import TaskManagerApp from './TaskManagerApp';
const queryClient = new QueryClient();
ReactDOM.render(
<QueryClientProvider client={queryClient}>
<React.StrictMode>
<TaskManagerApp />
</React.StrictMode>
</QueryClientProvider>,
document.getElementById('root')
);
In the above code we are using QueryClient and QueryClientProvider from React Query library, these are basically used for managing the global query cache and state of our React application.
This QueryClientProvider works as a wrapper and it wraps the entire application to make the QueryClient instance available for all the components.
There is one property called client on QueryClientProvider, You can assign a queryClient instance inside this property and this will ensure that the same query client is used throughout the application.
Now, its time to set up a JSON server to run our application
The JSON Server allows us to quickly set up a mock API server using a JSON file as a database. It provides a RESTful API that responds to HTTP requests and returns JSON data, just like a real API server.
Run the below command to install the JSON server
npm install json-server
This will also create a db.json file, which will be used to save our task for the tasks manager app.
{
"tasks": []
}
Now, to run our JSON server with our React Application, we need to update our package.json to add a script for starting the mock API server
"scripts": {
"start": "react-scripts start",
"start-api": "json-server --watch db.json --port 5000",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}
Run the below command to start both the React app and the mock API server
npm start
npm run start-api
Access the app at http://localhost:3000.
This was just a basic example to learn React Query for data fetching and mutations in our task manager applications. You can add more features, and error handling, and refine the user interface.
If you have any doubts, please comment. Happy Coding 🙂