Giới thiệu
Trong bài viết này, chúng ta sẽ tìm hiểu cách sử dụng cursor pagination trong ứng dụng React với Redux Toolkit. Cursor pagination là một kỹ thuật hữu ích để quản lý dữ liệu trong các ứng dụng có lượng thông tin lớn, giúp tối ưu hóa việc tải và hiển thị dữ liệu. Chúng ta sẽ cùng nhau xây dựng một ví dụ cụ thể để áp dụng kỹ thuật này.
Mục tiêu của bài viết
- Quản lý dữ liệu phân trang hiệu quả với cursor.
- Sử dụng Redux Toolkit để quản lý trạng thái ứng dụng.
- Tạo một giao diện người dùng đơn giản để hiển thị dữ liệu.
Nội dung bài viết
- 1. Slice của Redux
- 2. Cấu hình Store
- 3. Cung cấp Store trong ứng dụng
- 4. Tạo thành phần với Paginattion và Sắp xếp
- 5. Quy trình hoàn chỉnh
1. Slice của Redux
Đầu tiên, chúng ta sẽ tạo một slice cho pagination trong Redux. Dưới đây là mã nguồn cho slice này:
javascript
// store/paginationSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
// Thunk để lấy kết quả từ API với cursor
export const fetchPage = createAsyncThunk(
"pagination/fetchPage",
async ({ cursor, sort }, thunkAPI) => {
const response = await fetch(
`/api/items?cursor=${cursor || ""}&sort=${sort}`
);
const data = await response.json();
return data;
// Giả sử data = { items: [...], nextCursor: "abc", previousCursor: "xyz" }
}
);
const paginationSlice = createSlice({
name: "pagination",
initialState: {
items: [],
nextCursor: null,
previousCursor: null,
sort: "docdate:asc",
loading: false,
error: null,
},
reducers: {
changeSorting: (state, action) => {
state.sort = action.payload;
},
},
extraReducers: (builder) => {
builder
.addCase(fetchPage.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(fetchPage.fulfilled, (state, action) => {
state.loading = false;
state.items = action.payload.items;
state.nextCursor = action.payload.nextCursor;
state.previousCursor = action.payload.previousCursor;
})
.addCase(fetchPage.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message;
});
},
});
export const { changeSorting } = paginationSlice.actions;
export default paginationSlice.reducer;
Chú thích mã nguồn
fetchPage: Đây là một thunk dùng để gọi API và lấy dữ liệu phân trang.paginationSlice: Slice này quản lý trạng thái của các item, cursor và trạng thái loading/error.
2. Cấu hình Store
Tiếp theo, chúng ta sẽ cấu hình Redux store để sử dụng slice vừa tạo:
javascript
// store/index.js
import { configureStore } from "@reduxjs/toolkit";
import paginationReducer from "./paginationSlice";
export const store = configureStore({
reducer: {
pagination: paginationReducer,
},
});
Chú thích mã nguồn
configureStore: Hàm này cấu hình store với reducer cho pagination.
3. Cung cấp Store trong ứng dụng
Chúng ta cần cung cấp store cho ứng dụng React bằng cách sử dụng Provider:
javascript
// main.jsx
import React from "react";
import ReactDOM from "react-dom/client";
import { Provider } from "react-redux";
import { store } from "./store";
import App from "./App";
ReactDOM.createRoot(document.getElementById("root")).render(
<Provider store={store}>
<App />
</Provider>
);
Chú thích mã nguồn
Provider: Component này cung cấp Redux store cho toàn bộ ứng dụng.
4. Tạo thành phần với Paginattion và Sắp xếp
Giờ đây, chúng ta sẽ tạo một thành phần để hiển thị dữ liệu, cho phép người dùng phân trang và sắp xếp:
javascript
// App.jsx
import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { fetchPage, changeSorting } from "./store/paginationSlice";
export default function App() {
const { items, nextCursor, previousCursor, sort, loading, error } = useSelector(
(state) => state.pagination
);
const dispatch = useDispatch();
// Tải dữ liệu lần đầu tiên
useEffect(() => {
dispatch(fetchPage({ cursor: null, sort }));
}, [dispatch, sort]);
const handleNext = () => {
if (nextCursor) dispatch(fetchPage({ cursor: nextCursor, sort }));
};
const handlePrevious = () => {
if (previousCursor) dispatch(fetchPage({ cursor: previousCursor, sort }));
};
const handleSortChange = (e) => {
dispatch(changeSorting(e.target.value));
dispatch(fetchPage({ cursor: null, sort: e.target.value }));
};
return (
<div>
<h1>Danh sách kết quả</h1>
{loading && <p>Đang tải...</p>}
{error && <p>Lỗi: {error}</p>}
<select value={sort} onChange={handleSortChange}>
<option value="docdate:asc">Ngày ↑</option>
<option value="docdate:desc">Ngày ↓</option>
<option value="slug:asc">Slug ↑</option>
<option value="slug:desc">Slug ↓</option>
<option value="score:asc">Điểm số ↑</option>
<option value="score:desc">Điểm số ↓</option>
</select>
<ul>
{items.map((item) => (
<li key={item.id}>{item.title} — {item.date}</li>
))}
</ul>
<div>
<button disabled={!previousCursor} onClick={handlePrevious}>
← Trở lại
</button>
<button disabled={!nextCursor} onClick={handleNext}>
Tiếp theo →
</button>
</div>
</div>
);
}
Chú thích mã nguồn
- Thành phần này sẽ hiển thị danh sách các item, trạng thái loading và cho phép người dùng điều chỉnh sắp xếp.
5. Quy trình hoàn chỉnh (pseudocode)
- Người dùng mở trang →
useEffectgọifetchPage({cursor: null, sort}). - Redux chuyển trạng thái từ
pendingsangfulfilledvà cập nhậtitems,nextCursor,previousCursor. - Người dùng nhấn vào Tiếp theo → gọi
fetchPage({cursor: nextCursor, sort}). - API trả về trang tiếp theo → Redux cập nhật
itemsvà các cursor. - Người dùng thay đổi sắp xếp → gọi
changeSortingvà tải lại trang đầu tiên.
Thực hành tốt nhất
- Luôn kiểm tra trạng thái loading trước khi hiển thị dữ liệu.
- Xử lý lỗi một cách thân thiện với người dùng.
Những cạm bẫy thường gặp
- Không xử lý trường hợp không có dữ liệu trả về từ API.
- Quên cập nhật các cursor khi dữ liệu mới được tải.
Mẹo hiệu suất
- Giảm thiểu số lần gọi API bằng cách cache kết quả khi có thể.
- Sử dụng lazy loading cho các phần tử không cần thiết hiển thị ngay lập tức.
Câu hỏi thường gặp (FAQ)
H1: Cursor pagination là gì?
Cursor pagination là một kỹ thuật phân trang giúp tải dữ liệu theo từng phần nhỏ hơn, sử dụng các cursor để xác định vị trí của dữ liệu.
H2: Tại sao nên sử dụng Redux Toolkit?
Redux Toolkit giúp đơn giản hóa việc quản lý trạng thái trong ứng dụng React, giảm thiểu boilerplate code và cải thiện khả năng bảo trì.
Kết luận
Trong bài viết này, chúng ta đã tìm hiểu cách sử dụng cursor pagination với Redux Toolkit trong ứng dụng React. Phương pháp này không chỉ giúp cải thiện hiệu suất của ứng dụng mà còn mang đến trải nghiệm người dùng tốt hơn. Hãy thử áp dụng vào dự án của bạn và theo dõi sự khác biệt!
Lời kêu gọi hành động
Nếu bạn thấy bài viết này hữu ích, hãy chia sẻ và theo dõi chúng tôi để nhận thêm nhiều kiến thức về phát triển ứng dụng!