Table of Contents
In this article, we will see how to use React-Query to fetch the to do list from API and display it, add a new item to the list, and update the list using mutation and query invalidation.
Building the API
We can use json-server to quickly spin up a server.
Install it globally using the following command:
1npm install -g json-server
Create a json file named db.json
in a location of your choice with the following content:
1{2 "todos": [3 {4 "id": "odnv6g",5 "title": "Do the dishes"6 },7 {8 "id": "jhomrt",9 "title": "Publish a blog"10 }11 ]12}
Now start the server using the command:
1json-server --watch db.json --port 8765
The API will spin up at: http://localhost:8765/todos
React app setup
Create a react app using the following command:
1npx create-react-app react-query-invalidate
Now install react-query:
1npm install react-query
In the index.js add react-query provider:
1import React from "react"2import ReactDOM from "react-dom/client"3import "./index.css"4import App from "./App"5import { QueryClient, QueryClientProvider } from "react-query"6const queryClient = new QueryClient()78const root = ReactDOM.createRoot(document.getElementById("root"))9root.render(10 <QueryClientProvider client={queryClient}>11 <App />12 </QueryClientProvider>13)
Displaying the todo list
Now let's display the todo list using react-query in App.js.
1import React from "react"2import { useQuery } from "react-query"34const App = () => {5 // Fetch todos6 const { isLoading, error, data } = useQuery("todos", async () => {7 const response = await fetch("http://localhost:8765/todos")8 return response.json()9 })1011 if (isLoading) {12 return <div>Loading...</div>13 }1415 if (error) {16 return <div>Error: {error.message}</div>17 }1819 return (20 <div>21 <h1>Todo List</h1>22 <form>23 <input24 type="text"25 name="todoInput"26 placeholder="Enter a todo"27 required28 />29 <button type="submit">Add Todo</button>30 </form>31 <ul>32 {data.map(todo => (33 <li key={todo.id}>{todo.title}</li>34 ))}35 </ul>36 </div>37 )38}3940export default App
In the above code:
- We are using
useQuery
hook to fetch the todos from the API. - We are displaying a loading message while the data is being fetched.
- We are displaying an error message if there is an error while fetching the data.
- We are displaying the todo list if the data is fetched successfully.
Now if you run the app, you will see the following output:
Adding a new todo
The next thing to do is to add a new item to the list.
We will write a submit handler for the form:
1import React from "react"2import { useMutation, useQuery } from "react-query"34const App = () => {5 // Fetch todos6 const { isLoading, error, data } = useQuery("todos", async () => {7 const response = await fetch("http://localhost:8765/todos")8 return response.json()9 })1011 // Add todo mutation12 const addTodoMutation = useMutation(async newTodo => {13 const response = await fetch("http://localhost:8765/todos", {14 method: "POST",15 headers: {16 "Content-Type": "application/json",17 },18 body: JSON.stringify(newTodo),19 })20 return response.json()21 })2223 // Handler for submitting the form24 const handleSubmit = e => {25 e.preventDefault()26 const { value } = e.target.todoInput27 const newTodo = {28 id: Math.random().toString(36).substring(7), // Generate a random alphanumeric id29 title: value,30 }31 addTodoMutation.mutate(newTodo)32 e.target.reset()33 }3435 if (isLoading) {36 return <div>Loading...</div>37 }3839 if (error) {40 return <div>Error: {error.message}</div>41 }4243 return (44 <div>45 <h1>Todo List</h1>46 <form onSubmit={handleSubmit}>47 <input48 type="text"49 name="todoInput"50 placeholder="Enter a todo"51 required52 />53 <button type="submit">Add Todo</button>54 </form>55 <ul>56 {data.map(todo => (57 <li key={todo.id}>{todo.title}</li>58 ))}59 </ul>60 </div>61 )62}6364export default App
In the above code:
addTodoMutation
function is used to make API call and add a new todo item to the list.- In
handleSubmit
function, we are generating a random id for the new todo item and calling theaddTodoMutation
function.
Now if we run the application and add a new item to the list, it won't be reflected in the UI.
However, it will be saved in db.json
file.
1{2 "todos": [3 {4 "id": "odnv6g",5 "title": "Do the dishes"6 },7 {8 "id": "jhomrt",9 "title": "Publish a blog"10 },11 {12 "id": "7v72h",13 "title": "Mow the lawn"14 }15 ]16}
Updating the list using query invalidation
The final step is to update the UI when a new item is added.
We can use the onSuccess
callback of useMutation
hook to invalidate the query.
1import React from "react"2import { useQuery, useMutation, useQueryClient } from "react-query"34const App = () => {5 const queryClient = useQueryClient()67 // Fetch todos8 const { isLoading, error, data } = useQuery("todos", async () => {9 const response = await fetch("http://localhost:8765/todos")10 return response.json()11 })1213 // Add todo mutation14 const addTodoMutation = useMutation(15 async newTodo => {16 const response = await fetch("http://localhost:8765/todos", {17 method: "POST",18 headers: {19 "Content-Type": "application/json",20 },21 body: JSON.stringify(newTodo),22 })23 return response.json()24 },25 {26 onSuccess: () => {27 queryClient.invalidateQueries("todos")28 },29 }30 )3132 // Handler for submitting the form33 const handleSubmit = e => {34 e.preventDefault()35 const { value } = e.target.todoInput36 const newTodo = {37 id: Math.random().toString(36).substring(7), // Generate a random alphanumeric id38 title: value,39 }40 addTodoMutation.mutate(newTodo)41 e.target.reset()42 }4344 if (isLoading) {45 return <div>Loading...</div>46 }4748 if (error) {49 return <div>Error: {error.message}</div>50 }5152 return (53 <div>54 <h1>Todo List</h1>55 <form onSubmit={handleSubmit}>56 <input57 type="text"58 name="todoInput"59 placeholder="Enter a todo"60 required61 />62 <button type="submit">Add Todo</button>63 </form>64 <ul>65 {data.map(todo => (66 <li key={todo.id}>{todo.title}</li>67 ))}68 </ul>69 </div>70 )71}7273export default App
Now if you add a new item to the list, it will be reflected in the UI. You can check the network tab to see both the create and fetch API calls.
Source code
You can download the complete code from here.
Do follow me on twitter where I post developer insights more often!