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é