RTK Query предоставляет встроенную модель наблюдения за запросами, кэшем и жизненным циклом данных, что делает его удобным инструментом для построения наблюдаемой (observable) клиентской сетевой логики. Логирование и мониторинг в RTK Query не являются отдельной «надстройкой», а формируются через middleware, lifecycle-хуки, Redux DevTools и возможности API-слайсов.
В основе RTK Query лежит интеграция с Redux store. Любое действие — запрос, мутация, инвалидация кэша — проходит через Redux action pipeline. Это означает, что каждое событие можно:
extraReducersRTK Query генерирует стандартные Redux actions с предсказуемыми именами:
api/executeQuery/pendingapi/executeQuery/fulfilledapi/executeQuery/rejectedapi/executeMutation/pendingapi/executeMutation/fulfilledapi/executeMutation/rejectedЭти события формируют основу мониторинга.
RTK Query полностью совместим с Redux DevTools. Каждый запрос отображается как последовательность действий:
В DevTools можно видеть:
pending, fulfilled,
rejected)Особенность RTK Query заключается в том, что DevTools отражает не
только результат запроса, но и внутреннее состояние кэша
queries и mutations.
RTK Query позволяет подключать middleware, через которые можно перехватывать все действия API-слайса.
const rtkQueryLogger = (api) => (next) => (action) => {
if (action.type.startsWith('api/')) {
console.log('[RTK Query]', action.type, action);
}
return next(action);
};
Middleware регистрируется в store:
const store = configureStore({
reducer: {
[api.reducerPath]: api.reducer
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(api.middleware, rtkQueryLogger)
});
RTK Query предоставляет встроенные lifecycle-события для каждого endpoint.
onQueryStartedИспользуется для отслеживания начала запроса:
getUser: builder.query({
query: (id) => `/user/${id}`,
async onQueryStarted(arg, { queryFulfilled }) {
console.log('Запрос начат:', arg);
try {
const result = await queryFulfilled;
console.log('Запрос завершён:', result.data);
} catch (err) {
console.log('Ошибка запроса:', err);
}
}
});
queryFulfilled позволяет синхронно отследить:
Это даёт точную точку контроля без внешнего middleware.
Для сложных приложений часто вводится централизованный слой логирования, который объединяет:
const createApiLogger = () => ({
logRequestStart: (endpoint, args) => {},
logRequestSuccess: (endpoint, args, data, duration) => {},
logRequestError: (endpoint, args, error, duration) => {}
});
extraOptionsRTK Query позволяет передавать extraOptions в
endpoint:
getUser: builder.query({
query: (id) => `/user/${id}`,
extraOptions: {
track: true
},
async onQueryStarted(arg, { queryFulfilled, extra }) {
const start = Date.now();
try {
const { data } = await queryFulfilled;
const duration = Date.now() - start;
console.log('TRACK SUCCESS', arg, data, duration);
} catch (e) {
console.log('TRACK ERROR', arg, e);
}
}
});
Мониторинг производительности строится на измерении:
const measureQuery = async (queryFulfilled, label) => {
const start = performance.now();
try {
const result = await queryFulfilled;
const end = performance.now();
console.log(`${label}: ${end - start}ms`);
return result;
} catch (e) {
const end = performance.now();
console.log(`${label} failed: ${end - start}ms`);
throw e;
}
};
Кэш RTK Query хранится в Redux state в виде:
state.api.queriesstate.api.mutationsstate.api.subscriptionsconst selectCache = (state) => state.api.queries;
RTK Query использует подписки для управления актуальностью данных. Мониторинг подписок позволяет выявить:
state.api.subscriptions[queryCacheKey]
Каждая запись содержит количество активных подписчиков.
RTK Query поддерживает автоматические retry, которые также можно мониторить.
fetchBaseQueryconst baseQuery = fetchBaseQuery({
baseUrl: '/api',
prepareHeaders: (headers, { getState }) => {
return headers;
}
});
const baseQueryWithLogging = async (args, api, extraOptions) => {
const result = await baseQuery(args, api, extraOptions);
if (result.error) {
console.error('API ERROR:', {
endpoint: api.endpoint,
args,
error: result.error
});
}
return result;
};
RTK Query легко интегрируется с системами:
const reportError = (error, context) => {
fetch('/monitoring', {
method: 'POST',
body: JSON.stringify({ error, context })
});
};
Использование в onQueryStarted:
catch (err) {
reportError(err, {
endpoint: 'getUser',
arg
});
}
Собранные данные могут использоваться для построения метрик:
{
endpoint: 'getUser',
requests: 1200,
errors: 23,
avgTime: 180,
cacheHitRate: 0.67
}
Redux Toolkit предоставляет listenerMiddleware, который
удобно использовать для аналитики RTK Query.
listenerMiddleware.startListening({
matcher: api.endpoints.getUser.matchFulfilled,
effect: async (action, listenerApi) => {
console.log('User loaded:', action.meta.arg);
}
});
Можно подписаться на все события API:
listenerMiddleware.startListening({
matcher: (action) => action.type.startsWith('api/'),
effect: (action) => {
console.log('API EVENT:', action.type);
}
});
Это позволяет построить полноценную систему аудита сетевых запросов.
В зрелых приложениях логирование RTK Query обычно делится на уровни:
Каждый уровень решает свою задачу и не дублирует другой.