React Query - Stack chất lượng với Frontend DEV
Lướt qua 1 số trang tuyển dụng thì mình có đọc được 1 số thông tin tuyển dụng yêu cầu kinh nghiệm về react-query.
Xem thông tin trên npmjs và github thì con số rất ấn tượng với 1,466,787 lượt tải hàng tuần + 41.9k stars vào thời điểm mình viết bài. Vậy hãy cùng tìm hiểu những kiến thức cơ bản về package so hot này nhé. 😘😘
React Query là gì
React-query là 1 thư viện data-fetching dành cho react. Nó có thể fetching, caching, đồng bộ và update data sau khi lấy từ database. Bạn có thể hiểu nó như 1 hệ thống caching mini bên dưới local vậy.
React Query có thể làm gì
Hãy cùng so sánh 1 đoạn code có và không có react-query để thấy được sự khác nhau nhé
Case không sử dụng react-query trong fetching data
Dưới đây là 1 ví dụ về việc fetching data thông thường. Ta sẽ sử dụng useEffect và 3 state nữa để lưu trạng thái của fetch. Bao gồm loading, error, data.
import React, {useState, useEffect} from 'react';
import axios from 'axios';
// regular fetch with axios
function App() {
const [isLoading, setLoading] = useState(false)
const [isError, setError] = useState(false)
const [data, setData] = useState({});
useEffect(() => {
const fetchData = async () => {
setError(false);
setLoading(true);
try {
const response = await axios('http://swapi.dev/api/people/1/');
setData(response.data);
} catch (error) {
setError(true);
}
setLoading(false);
};
fetchData()
}, []);
return (
<div className="App">
<h1>React Query example with Star Wars API</h1>
{isError && <div>Something went wrong ...</div>}
{isLoading ? (
<div>Loading ...</div>
) : (
<pre>{JSON.stringify(data, null, 2)}
</pre>
)}
</div>
);
}
export default App;
Case sử dụng react-query để fetch data
import React from 'react';
import axios from 'axios';
import {useQuery} from 'react-query';
function App() {
const { isLoading, error, data } = useQuery('posts', () =>
axios('http://swapi.dev/api/people/1/'))
return (
<div className="App">
<h1>React Query example with star wars API</h1>
{error && <div>Something went wrong ...</div>}
{isLoading ? (
<div>Retrieving Luke Skywalker Information ...</div>
) : (
<pre>{JSON.stringify(data, null, 2)}
</pre>
)}
</div>
);
}
export default App;
Sau khi fetch thì data đã được cache qua key posts. Và ae có thể thấy được react-query hỗ trợ luôn việc xử lý loading, error, data.
Access cache data ở 1 component khác
Rất tiện phải không. Thay vì sử dụng redux hay truyền qua props, ae có thể access luôn data đã cache bằng react-query. Ae để ý tham số posts khi fetch data khi muốn access nó.
import { useQuery } from '@tanstack/react-query';
function CachedPosts() {
const { data, isLoading, error } = useQuery(['posts']);
if (isLoading) return <p>Loading cached posts...</p>;
if (error) return <p>Error loading cached posts.</p>;
return (
<div>
<h2>Cached Posts:</h2>
{data.map(post => (
<div key={post.id}>{post.title}</div>
))}
</div>
);
}
export default CachedPosts;
Add or edit data cache đơn giản và ngắn gọn
import { useQueryClient } from 'react-query';
const Component = () => {
const queryClient = useQueryClient();
const addOrUpdateData = () => {
// Example of updating cache for a query with key 'todos'
queryClient.setQueryData(['todos'], (oldData) => {
return [...(oldData || []), { id: 4, title: 'New Todo' }];
});
};
return <button onClick={addOrUpdateData}>Add/Update Todo</button>;
};
useMutation
React query đã thiết kế useQuery để sử dụng fetdata. Và useMutaion để thực điện các action thay đổi data như add, edit, delete. Và đây là 1 ví dụ về 1 case sử dụng.
import { useMutation, useQueryClient } from '@tanstack/react-query';
import axios from 'axios';
const createPost = async (newPost) => {
const { data } = await axios.post('/api/posts', newPost);
return data;
};
function CreatePost() {
const queryClient = useQueryClient();
const mutation = useMutation(createPost, {
onMutate: async (newPost) => {
await queryClient.cancelQueries('posts');
const previousPosts = queryClient.getQueryData('posts');
queryClient.setQueryData('posts', (old) => [...old, newPost]);
return { previousPosts };
},
onError: (err, newPost, context) => {
queryClient.setQueryData('posts', context.previousPosts);
},
onSuccess: () => {
queryClient.invalidateQueries('posts');
},
onSettled: () => {
queryClient.invalidateQueries('posts');
},
});
const handleCreatePost = () => {
mutation.mutate({ title: 'New Post', content: 'This is a new post' });
};
return (
<div>
<button onClick={handleCreatePost} disabled={mutation.isLoading}>
{mutation.isLoading ? 'Creating Post...' : 'Create Post'}
</button>
{mutation.isError && <p>Error creating post.</p>}
{mutation.isSuccess && <p>Post created successfully!</p>}
</div>
);
}
export default CreatePost;
- queryClient.removeQueries(['todos']); : sử dụng để remove data cache
- queryClient.invalidateQueries(['todos']);: Như 1 flag để biết rằng data todos này đã cũ. Lần fetch tiếp theo sẽ call lại api
- queryClient.prefetchQuery(['todos'], fetchTodos); Hoặc bạn cần call luôn api
- @tanstack/react-query-devtools : là 1 tool để bạn có thể view được data đã cache
Tổng kết:
Ưu điểm:
- Clearn code, hạn chế phải khai báo nhiều state và thay thể 1 phần code dài dòng của redux
- Hỗ trợ tốt, tiết kiệm thời gian cho dev về fetch data và tương tác với server data
- Hữu ích cho các ứng dụng muốn tối ưu mạnh ở client về fetching data và tương tác với server data
Nhược điểm:
- FE cần quản lý tốt tầng data cache này không thì sẽ là 1 luồng bug mới dành cho tester
- Việc sử dụng đan xen redux và react-query có thể sẽ gây rối cho luồng code chung
End:
- Trong 1 môi trường IT đào thải nhanh chóng thì việc update tech là việc hết sức quan trọng. Và React query xứng đáng để bạn tìm hiểu nó
- Trước khi áp dụng vào dự án ae nên trao đổi kỹ với techlead và member trong team để mn cùng nắm đc nhé
- Bài viết có gì sai sót mong ae comment cùng thảo luận nhé
All rights reserved