visit
According to the , “RTK Query is a powerful data fetching and caching tool. It is designed to simplify common cases for loading data in a web application, eliminating the need to hand-write data fetching & caching logic yourself.”
For example, I once tried to use it to query some table data and change it -- in other words, basic CRUD operations. I was faced, however, with an issue when I wanted to add additional data to objects and update that data without calling the API.
For better code readability, I realized it’s possible to use the API splitting approach and created baseApi
:
export const baseApi = createApi({
reducerPath: 'baseApi',
tagTypes: ['Notifications'],
baseQuery: fetchBaseQuery({ baseUrl: getBaseUrl() }),
endpoints: () => ({}),
});
For the API, which I need to query, I then wrote notificationsApi
:
const notificationsApi = baseApi.injectEndpoints({
endpoints: build => ({
fetch: build.query<INotification[], INotificationBaseRequest>({
query: buildUrl,
transformResponse: (x: IResponse<INotification[]>) => x.result,
providesTags: ['Notifications'],
}),
remove: build.mutation<void, IRemoveNotificationRequest>({
query: arg => ({
url: buildUrl(arg),
method: 'DELETE',
}),
invalidatesTags: (_: any, id: any) => [{ type: 'Notifications', id }],
}),
removeAll: build.mutation<void, INotificationBaseRequest>({
query: arg => ({
url: buildUrl(arg),
method: 'DELETE',
}),
invalidatesTags: ['Notifications'],
}),
}),
});
export const { useFetchQuery, useRemoveMutation, useRemoveAllMutation } = notificationsApi;
Where buildUrl
is a simple function that combines URL arguments in one string, such as notification ID to ‘baseUrl/notifications/{id}’.
In the endpoints
section I introduced three operations that I needed to use.
The fetch
operation retrieves data by GET request
.
[ { id: number; name: string; message: string; }, ... ]
This array I can easily get in component via the useFecthQuery
hook.
const { data, isLoading } = useFetchQuery({ ...params });
Here, I don’t need to implement isLoading
logic that actually describes the status of the HTTP request.
However, please be careful, the
isLoading
is for the first query only.
For common casesisFetching
is more appropriate. The hook will automatically request data (in case if there is no data or the cache is invalid).
The remove
operation is used to send a DELETE request and remove one notification.
The invalidatesTags
is there to remove only one entry from the array by id.
const [remove] = useRemoveMutation();
You can call remove
on a button click or another user action. As well as the removeAll
operation.
const [removeAll, { isLoading: isDeleting }] = useRemoveAllMutation();
Also in such an operation, there is a possibility to use properties to understand the status of HTTP requests. The main difference between remove
and removeAll
is that in removeAll I remove the whole cache.
But I understood that I want to extend objects in the array, to have an additional property: isCollapsed
. It can not be done easily - just changing the current state of cached objects.
First of all, I could create my own state NotificationState
, where there will be additional data stored, of course, I need to createSlice
or createReducer
and add more actions.
Or I will not use RTK Query, and all will be done via createSlice
where objects will be extended with the required fields.
The general takeaway here is, if for some reason you need to extend objects, or in your API, objects come in different schemas and you want to store it all in one place, it is better to manage the state by yourself from the begining.