Sekarang, mari kita lanjutkan dengan materi **Implementasi React Query untuk Aplikasi yang Mengambil Data dari API**. Dalam contoh ini, kita akan menggunakan aplikasi React untuk mengkonsumsi data dari API eksternal dengan fitur pengambilan dan mutasi data yang telah kita pelajari sebelumnya.
### Studi Kasus: Aplikasi Todo List dengan API
Aplikasi ini akan memiliki dua fitur utama:
1. **Pengambilan Data (GET)** – Mengambil daftar todo dari API menggunakan `useQuery`.
2. **Menambah Data (POST)** – Menambahkan todo baru ke dalam daftar menggunakan `useMutation`.
Kita akan menggunakan API publik dari **JSONPlaceholder** untuk mensimulasikan data Todo.
#### Struktur Proyek
Berikut adalah struktur dasar dari aplikasi kita:
src/
│
├── components/
│ ├── TodoList.js // Komponen untuk menampilkan daftar todo
│ ├── AddTodo.js // Komponen untuk menambahkan todo baru
│
├── App.js // Komponen utama yang menyatukan semuanya
└── index.js // File entry point yang menginisialisasi QueryClient
### Langkah Implementasi
#### 1. **Mengambil Data Todo Menggunakan `useQuery`**
Buat file `TodoList.js` di folder `components/` untuk mengambil dan menampilkan daftar todo dari API.
```jsx
// components/TodoList.js
import React from 'react';
import { useQuery } from 'react-query';
import axios from 'axios';
const fetchTodos = async () => {
const response = await axios.get('https://jsonplaceholder.typicode.com/todos');
return response.data;
};
function TodoList() {
const { data, isLoading, isError, error } = useQuery('todos', fetchTodos);
if (isLoading) return <div>Loading...</div>;
if (isError) return <div>Error: {error.message}</div>;
return (
<div>
<h1>Todo List</h1>
<ul>
{data.map(todo => (
<li key={todo.id}>
{todo.title} {todo.completed ? '(Completed)' : ''}
</li>
))}
</ul>
</div>
);
}
export default TodoList;
Penjelasan:
- **`useQuery('todos', fetchTodos)`**: Mengambil data dari API dengan key `'todos'`, yang mengidentifikasi request ini di cache.
- Jika query sedang loading, tampilkan **Loading**.
- Jika ada error, tampilkan pesan error.
- Jika sukses, tampilkan daftar todo.
#### 2. **Menambahkan Todo Baru Menggunakan `useMutation`**
Selanjutnya, buat file `AddTodo.js` di folder `components/`. Komponen ini akan memungkinkan pengguna menambahkan todo baru menggunakan `useMutation`.
```jsx
// components/AddTodo.js
import React, { useState } from 'react';
import { useMutation, useQueryClient } from 'react-query';
import axios from 'axios';
const addTodo = async (newTodo) => {
const response = await axios.post('https://jsonplaceholder.typicode.com/todos', newTodo);
return response.data;
};
function AddTodo() {
const [title, setTitle] = useState('');
const queryClient = useQueryClient();
const mutation = useMutation(addTodo, {
onSuccess: () => {
// Invalidate and refetch the 'todos' query to update the todo list
queryClient.invalidateQueries('todos');
},
});
const handleSubmit = (e) => {
e.preventDefault();
mutation.mutate({ title, completed: false });
setTitle(''); // Reset input field
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Enter new todo"
required
/>
<button type="submit">Add Todo</button>
{mutation.isLoading && <p>Adding todo...</p>}
{mutation.isError && <p>Error: {mutation.error.message}</p>}
{mutation.isSuccess && <p>Todo added successfully!</p>}
</form>
);
}
export default AddTodo;
Penjelasan:
- **`useMutation(addTodo)`**: Fungsi ini mengirimkan data baru ke API (menggunakan POST request) dan memperbarui cache menggunakan `queryClient.invalidateQueries('todos')` untuk memastikan bahwa daftar todo di-refresh setelah penambahan.
- Komponen ini juga menampilkan status loading, error, dan pesan sukses.
#### 3. **Menyatukan Komponen di `App.js`**
Sekarang kita gabungkan komponen-komponen tersebut di dalam `App.js`.
```jsx
// App.js
import React from 'react';
import TodoList from './components/TodoList';
import AddTodo from './components/AddTodo';
function App() {
return (
<div>
<h1>Todo App with React Query</h1>
<AddTodo />
<TodoList />
</div>
);
}
export default App;
#### 4. **Konfigurasi QueryClient di `index.js`**
Konfigurasikan React Query di file `index.js` untuk menyediakan `QueryClientProvider` ke seluruh aplikasi.
```jsx
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { QueryClient, QueryClientProvider } from 'react-query';
import App from './App';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
const queryClient = new QueryClient();
ReactDOM.render(
<QueryClientProvider client={queryClient}>
<App />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>,
document.getElementById('root')
);
### Hasil Akhir
- Aplikasi akan menampilkan daftar todo yang diambil dari API di halaman utama.
- Pengguna dapat menambahkan todo baru dengan mengetikkan judul di input form dan mengklik tombol **Add Todo**.
- Setiap kali todo baru ditambahkan, daftar todo akan di-refresh secara otomatis untuk mencerminkan perubahan.
### Penjelasan Lebih Lanjut
- **useQuery**: Dipakai untuk pengambilan data secara efisien, mendukung caching, polling, dan re-fetching otomatis.
- **useMutation**: Dipakai untuk operasi mutasi data (POST, PUT, DELETE), dan memungkinkan pengelolaan perubahan data secara optimis atau asinkron.
- **invalidateQueries**: Digunakan setelah mutasi untuk memberitahukan React Query agar melakukan re-fetch pada query tertentu, sehingga data terbaru ditampilkan.
- **React Query Devtools**: Ini adalah tool yang berguna untuk memantau status query dan cache secara real-time, terutama untuk debugging.
### Tantangan dan Optimasi
- Kamu bisa mencoba mengimplementasikan fitur seperti **pagination** atau **infinite scrolling** pada daftar todo jika API mendukung.
- Jika API lambat, cobalah mengoptimalkan aplikasi dengan **optimistic updates** agar interaksi pengguna terasa lebih cepat.