Ta gọi các request truy vấn dữ liệu được thực hiện bởi RTK Query là các query.
Để thực hiện truy vấn dữ liệu từ API bằng RTK Query, ta cần:
- Định nghĩa các query endpoint khi tạo ra API slice.
- Gọi sử dụng hook của API slice để lấy ra dữ liệu.
Defining Query Endpoints
Các query endpoint của một API slice được định nghĩa thông qua phương thức builder.query
:
endpoints: (builder) => ({
endpoint: builder.query({
// ...
})
})
Phương thức này nhận vào một đối tượng bao gồm nhiều thuộc tính. Một số thuộc tính quan trọng:
Query
Thuộc tính query
là một callback giúp xây dựng URL của request.
query: (name) => ({
url: `pokemon/${name}`
})
Ta cũng có thể truyền vào query
một object:
query: ({ limit, offset }) => ({
url: `pokemon?limit=${limit}&offset=${offset}`
})
Cũng có thể thêm các custom header vào request thông qua đối tượng trả về của query
:
query: (name) => ({
url: `pokemon/${name}`,
'X-API-Key': `${process.env.API_KEY}`
})
Transform
Thuộc tính transformResponse
cho phép thực hiện biến đổi response nhận được.
transformResponse: (response, meta, arg) => response.data
Ví dụ, ta có thể thêm vào ID cố định cho các phần tử của mảng dữ liệu results
có trong kết quả trả về như sau:
transformResponse: (response) => {
return response.results.map((item, index) => ({
...item,
id: index
}))
}
Thuộc tính transformErrorResponse
sẽ giúp biến đổi lỗi nhận được.
transformErrorResponse: (response, meta, arg) => response.status
Performing Queries with React Hooks
Ta gọi tất cả các hook tương ứng với các query endpoint ở trong các API slice là useQuery
.
Query Hook Options
Các hook useQuery
sẽ nhận hai đối số:
args
: có thể là một biến hoặc một đối tượng bao gồm nhiều thuộc tính truyền vào callback củaquery
.queryOptions
: là một đối tượng bao gồm nhiều thuộc tính giúp kiểm soát hành vi của việc lấy dữ liệu. Một số thuộc tính quan trọng:skip
: bỏ qua việc lấy dữ liệu, mặc định làfalse
.pollingInterval
: cho phép thực hiện re-fetch theo một chu kỳ nào đó.selectFromResult
: cho phép lấy ra một phần nhỏ của dữ liệu trong kết quả trả về.
Giả sử ta có query endpoint sau:
endpoints: (builder) => ({
getPokemonByName: builder.query({
query: (name) => ({ url: `pokemon/${name}` })
})
})
Hook tương ứng của query endpoint sẽ là useGetPokemonByNameQuery
. Gọi sử dụng hook này như sau:
useGetPokemonByNameQuery("pikachu",{ pollingInterval: 3000 })
Bằng cách sử dụng thuộc tính pollingInterval
với giá trị là 3000
, dữ liệu sẽ được re-fetch mỗi 3 giây một lần.
Frequently Used Query Hook Return Values
Giá trị trả về từ useQuery
là một đối tượng gồm nhiều thuộc tính. Một số thuộc tính thường dùng:
data
: lưu dữ liệu trả về.isLoading
: chỉ ra rằng query đang được xử lý lần đầu tiên và chưa có dữ liệu tại thời điểm này. Mang giá trịtrue
đối với request đầu tiên.isFetching
: chỉ ra rằng query đang được xử lý và có thể đã có dữ liệu trước đó. Mang giá trịtrue
đối với cả request đầu tiên và các request sau đó.
Thuộc tính isLoading
có thể dùng để hiển thị skeleton khi component được hiển thị lần đầu tiên và chưa có dữ liệu. Trong khi đó, thuộc tính isFetching
có thể dùng để grey out giao diện cũ khi người dùng thực hiện chuyển từ trang 1 sang trang 2.
Ví dụ:
function Pokemon() {
const { data: pokemon, isLoading, isFetching } = useGetPokemonByNameQuery(
"pikachu",
{ pollingInterval: 3000 }
)
if (isLoading) return <div>Loading...</div>
if (!pokemon) return <div>Missing pokemon!</div>
return (
<div>
{pokemon.name} {isFetching ? "...refetching" : ""}
</div>
)
}
Component trên có một số đặc điểm sau:
- Nó sẽ chỉ hiển thị dòng chữ
"Loading..."
khi query đang được xử lý và chưa có dữ liệu ở trong cache. - Khi query được retrigger sau 3 giây (do sử dụng option
pollingInterval
) thì nó sẽ thêm vào dòng chữ"...refetching"
ở sau tên của Pokémon.
Selecting Data From a Query Result
Trong trường hợp parent component sử dụng RTK Query để lấy dữ liệu và ta muốn truy xuất một phần nhỏ của kết quả trả về ở trong child component. Khi đó, ta có thể dùng option selectFromResult
của hook useQuery
.
Ví dụ, giả sử có component PokemonList
như sau:
function PokemonList() {
const { data: pokemons } = useGetPokemonsQuery({ limit: 100, offset: 0 })
return (
<ul>
{pokemons?.map((pokemon) => (
<Pokemon id={pokemon.id} key={pokemon.id} />
))}
</ul>
)
}
Có thể thấy, component này sử dụng hook useGetPokemonsQuery
. Dữ liệu trả về từ hook được truyền vào các child component.
Thay vì gọi sử dụng hook useGetPokemonByNameQuery
(lấy thông tin của Pokemon dựa trên tên) ở từng child component, ta có thể gọi sử dụng useGetPokemonsQuery
với option selectFromResult
như sau:
function Pokemon({ id }) {
const { pokemon } = useGetPokemonsQuery(
{ limit: 100, offset: 0 },
{
selectFromResult: ({ data: pokemons }) => ({
pokemon: pokemons?.find((pokemon) => pokemon.id === id)
})
}
)
return <li>{pokemon?.name}</li>
}
Giá trị trả về của selectFromResult
là dữ liệu mà ta muốn truy xuất từ query result của parent component.
Bằng cách này, sẽ chỉ có duy nhất một request được gửi đi ở parent component. Ngoài ra, các child component cũng chỉ re-render khi dữ liệu tương ứng với nó bị thay đổi.
Related
list
from [[Queries in RTK Query]]
sort file.ctime asc