← Назад к вопросам

В чем разница между RTK и RTK Query?

2.3 Middle🔥 181 комментариев
#React#State Management

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

RTK vs RTK Query

RTK (Redux Toolkit) и RTK Query — это две части экосистемы управления состоянием Redux, но они решают разные задачи. RTK — это инструмент для управления состоянием приложения, а RTK Query — специализирована для работы с серверными данными и кешированием.

Redux Toolkit (RTK)

RTK — это официальный инструмент для упрощения работы с Redux. Он скрывает сложность Redux под удобным API и включает популярные middleware вроде Redux Thunk.

// Создание слайса (reducer + actions)
import { createSlice } from '@reduxjs/toolkit';

const userSlice = createSlice({
  name: 'user',
  initialState: { data: null, loading: false, error: null },
  reducers: {
    setUser: (state, action) => {
      state.data = action.payload;
    },
    clearUser: (state) => {
      state.data = null;
    }
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchUser.pending, (state) => {
        state.loading = true;
      })
      .addCase(fetchUser.fulfilled, (state, action) => {
        state.data = action.payload;
        state.loading = false;
      })
      .addCase(fetchUser.rejected, (state, action) => {
        state.error = action.payload;
        state.loading = false;
      });
  }
});

// Async thunk для асинхронных операций
import { createAsyncThunk } from '@reduxjs/toolkit';

const fetchUser = createAsyncThunk(
  'user/fetchUser',
  async (userId: number) => {
    const response = await fetch(`/api/users/${userId}`);
    return response.json();
  }
);

RTK Query

RTK Query — это встроенная в Redux Toolkit библиотека для работы с серверными данными. Она автоматически управляет кешированием, синхронизацией и жизненным циклом данных.

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

const userApi = createApi({
  reducerPath: 'userApi',
  baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
  endpoints: (builder) => ({
    getUserById: builder.query({
      query: (userId) => `/users/${userId}`,
      // Автоматическое кеширование, синхронизация, etc.
    }),
    updateUser: builder.mutation({
      query: ({ userId, ...patch }) => ({
        url: `/users/${userId}`,
        method: 'PATCH',
        body: patch,
      }),
      // Автоматическое инвалидирование кеша
    }),
  }),
});

// Использование в компонентах
const { data: user, isLoading, error } = userApi.useGetUserByIdQuery(123);
const [updateUser] = userApi.useUpdateUserMutation();

Сравнение основных различий

АспектRTKRTK Query
НазначениеУправление состоянием приложенияРабота с серверными данными
КешированиеРучное управлениеАвтоматическое
СинхронизацияРучнаяАвтоматическая
API запросыНужен createAsyncThunkВстроено в createApi
КодБольше boilerplateОчень компактно
СложностьСредняяНизкая (для серверных данных)

Подробное сравнение на примере

RTK подход (много кода):

const postSlice = createSlice({
  name: 'posts',
  initialState: { items: [], loading: false, error: null },
  reducers: {
    setLoading: (state, action) => {
      state.loading = action.payload;
    },
    setItems: (state, action) => {
      state.items = action.payload;
    },
    setError: (state, action) => {
      state.error = action.payload;
    },
    addItem: (state, action) => {
      state.items.push(action.payload);
    },
    updateItem: (state, action) => {
      const index = state.items.findIndex(p => p.id === action.payload.id);
      if (index !== -1) state.items[index] = action.payload;
    },
    deleteItem: (state, action) => {
      state.items = state.items.filter(p => p.id !== action.payload);
    }
  }
});

const fetchPosts = createAsyncThunk(
  'posts/fetchPosts',
  async () => {
    const response = await fetch('/api/posts');
    return response.json();
  }
);

const createPost = createAsyncThunk(
  'posts/createPost',
  async (post) => {
    const response = await fetch('/api/posts', {
      method: 'POST',
      body: JSON.stringify(post)
    });
    return response.json();
  }
);

// Много extraReducers для обработки...

RTK Query подход (компактно):

const postsApi = createApi({
  reducerPath: 'postsApi',
  baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
  endpoints: (builder) => ({
    getPosts: builder.query({
      query: () => '/posts',
    }),
    createPost: builder.mutation({
      query: (post) => ({
        url: '/posts',
        method: 'POST',
        body: post,
      }),
      invalidatesTags: ['Post'], // Автоматическое инвалидирование
    }),
    updatePost: builder.mutation({
      query: ({ id, ...patch }) => ({
        url: `/posts/${id}`,
        method: 'PATCH',
        body: patch,
      }),
      invalidatesTags: ['Post'],
    }),
    deletePost: builder.mutation({
      query: (id) => ({
        url: `/posts/${id}`,
        method: 'DELETE',
      }),
      invalidatesTags: ['Post'],
    }),
  }),
});

Использование в компонентах

RTK:

import { useDispatch, useSelector } from 'react-redux';

function PostsList() {
  const dispatch = useDispatch();
  const { items, loading } = useSelector(state => state.posts);
  
  useEffect(() => {
    dispatch(fetchPosts());
  }, []);
  
  return loading ? <Loader /> : <div>{items.map(p => <Post key={p.id} post={p} />)}</div>;
}

RTK Query:

function PostsList() {
  const { data: items, isLoading } = postsApi.useGetPostsQuery();
  
  return isLoading ? <Loader /> : <div>{items?.map(p => <Post key={p.id} post={p} />)}</div>;
}

Когда использовать что

Используй RTK для:

  • Локального состояния приложения (UI состояния, фильтры, модали)
  • Сложной бизнес-логики
  • Состояния, которое не приходит с сервера
  • Синхронизации между несколькими компонентами

Используй RTK Query для:

  • Работы с REST API
  • Кеширования серверных данных
  • CRUD операций
  • Синхронизации данных с сервером
  • Оптимистичных обновлений

Комбинированный подход

const store = configureStore({
  reducer: {
    // Локальное состояние
    ui: uiSlice.reducer,
    filters: filtersSlice.reducer,
    // Серверные данные
    [postsApi.reducerPath]: postsApi.reducer,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(postsApi.middleware),
});

Вывод

RTK Query является частью Redux Toolkit и специализирована для серверных данных, RTK — для общего управления состоянием. В современных приложениях обычно используют оба: RTK Query для работы с API и RTK для локального UI состояния. Это позволяет избежать boilerplate и получить мощное кеширование автоматически.