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

Как импортировать слайс в Redux-стор?

1.7 Middle🔥 241 комментариев
#State Management

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

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

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

Что такое Redux Slice

Redux Slice - это набор редьюсера, экшнов и состояния, объединённые в один модуль. Это часть Redux Toolkit (@reduxjs/toolkit), которая значительно упростила работу с Redux, избавив разработчиков от необходимости писать множество boilerplate кода.

Структура Redux Slice

// src/features/user/userSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

interface UserState {
  name: string;
  age: number;
  email: string;
}

const initialState: UserState = {
  name: 'Иван',
  age: 28,
  email: 'ivan@example.com'
};

const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {
    setName: (state, action: PayloadAction<string>) => {
      state.name = action.payload;
    },
    setAge: (state, action: PayloadAction<number>) => {
      state.age = action.payload;
    },
    updateUser: (state, action: PayloadAction<UserState>) => {
      return action.payload; // Можно заменить весь state
    }
  }
});

export const { setName, setAge, updateUser } = userSlice.actions;
export default userSlice.reducer;

Как импортировать Slice в Store

Базовое объединение слайсов

// src/store/store.ts
import { configureStore } from '@reduxjs/toolkit';
import userReducer from '../features/user/userSlice';
import postsReducer from '../features/posts/postsSlice';
import authReducer from '../features/auth/authSlice';

const store = configureStore({
  reducer: {
    user: userReducer,
    posts: postsReducer,
    auth: authReducer
  }
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

export default store;

Импорт reducer из slice

Когда вы вызываете createSlice, он автоматически создаёт reducer. Экспортируйте его по умолчанию (default export) из файла slice:

// src/features/comments/commentsSlice.ts
const commentsSlice = createSlice({
  name: 'comments',
  initialState: [],
  reducers: { /* ... */ }
});

export default commentsSlice.reducer; // Главный экспорт для store

Тогда в store импортируйте просто:

import commentsReducer from '../features/comments/commentsSlice';

Практический пример: Полная структура

1. Создаём слайс

// src/features/todos/todosSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

interface Todo {
  id: string;
  title: string;
  completed: boolean;
}

interface TodosState {
  items: Todo[];
  loading: boolean;
  error: string | null;
}

const initialState: TodosState = {
  items: [],
  loading: false,
  error: null
};

const todosSlice = createSlice({
  name: 'todos',
  initialState,
  reducers: {
    addTodo: (state, action: PayloadAction<Todo>) => {
      state.items.push(action.payload);
    },
    removeTodo: (state, action: PayloadAction<string>) => {
      state.items = state.items.filter(todo => todo.id !== action.payload);
    },
    toggleTodo: (state, action: PayloadAction<string>) => {
      const todo = state.items.find(t => t.id === action.payload);
      if (todo) {
        todo.completed = !todo.completed;
      }
    },
    setLoading: (state, action: PayloadAction<boolean>) => {
      state.loading = action.payload;
    }
  }
});

export const { addTodo, removeTodo, toggleTodo, setLoading } = todosSlice.actions;
export default todosSlice.reducer;

2. Создаём store с импортированным слайсом

// src/store/store.ts
import { configureStore } from '@reduxjs/toolkit';
import todosReducer from '../features/todos/todosSlice';

const store = configureStore({
  reducer: {
    todos: todosReducer
  }
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

export default store;

3. Используем в приложении

// src/App.tsx
import { Provider } from 'react-redux';
import store from './store/store';
import TodosContainer from './features/todos/TodosContainer';

function App() {
  return (
    <Provider store={store}>
      <TodosContainer />
    </Provider>
  );
}

export default App;

4. Используем в компонентах

// src/features/todos/TodosContainer.tsx
import { useDispatch, useSelector } from 'react-redux';
import { RootState, AppDispatch } from '../../store/store';
import { addTodo, removeTodo, toggleTodo } from './todosSlice';

function TodosContainer() {
  const dispatch = useDispatch<AppDispatch>();
  const todos = useSelector((state: RootState) => state.todos.items);
  const loading = useSelector((state: RootState) => state.todos.loading);

  const handleAddTodo = (title: string) => {
    dispatch(addTodo({
      id: Date.now().toString(),
      title,
      completed: false
    }));
  };

  const handleToggle = (id: string) => {
    dispatch(toggleTodo(id));
  };

  const handleRemove = (id: string) => {
    dispatch(removeTodo(id));
  };

  return (
    <div>
      <h1>Мои задачи</h1>
      {loading && <p>Загрузка...</p>}
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>
            <input
              type="checkbox"
              checked={todo.completed}
              onChange={() => handleToggle(todo.id)}
            />
            {todo.title}
            <button onClick={() => handleRemove(todo.id)}>Удалить</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default TodosContainer;

Несколько слайсов в одном стора

// src/store/store.ts
import { configureStore } from '@reduxjs/toolkit';

import userReducer from '../features/user/userSlice';
import authReducer from '../features/auth/authSlice';
import todosReducer from '../features/todos/todosSlice';
import postsReducer from '../features/posts/postsSlice';
import notificationsReducer from '../features/notifications/notificationsSlice';

const store = configureStore({
  reducer: {
    user: userReducer,
    auth: authReducer,
    todos: todosReducer,
    posts: postsReducer,
    notifications: notificationsReducer
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware()
      .concat(/* custom middleware если нужно */)
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

export default store;

Советы и лучшие практики

Типизация состояния

// Создайте отдельный файл для типов
// src/features/user/types.ts
export interface User {
  id: string;
  name: string;
  email: string;
  role: 'admin' | 'user';
}

export interface UserState {
  data: User | null;
  loading: boolean;
  error: string | null;
}

Селекторы для удобного доступа

// src/features/user/userSlice.ts
export const selectUser = (state: RootState) => state.user.data;
export const selectUserLoading = (state: RootState) => state.user.loading;
export const selectUserError = (state: RootState) => state.user.error;

// В компоненте
const user = useSelector(selectUser);

Асинхронные операции с Thunk

import { createAsyncThunk } from '@reduxjs/toolkit';

export const fetchUser = createAsyncThunk(
  'user/fetchUser',
  async (userId: string, { rejectWithValue }) => {
    try {
      const response = await fetch(`/api/users/${userId}`);
      return await response.json();
    } catch (error) {
      return rejectWithValue('Ошибка загрузки');
    }
  }
);

// В слайсе
extraReducers: (builder) => {
  builder
    .addCase(fetchUser.pending, (state) => {
      state.loading = true;
    })
    .addCase(fetchUser.fulfilled, (state, action) => {
      state.loading = false;
      state.data = action.payload;
    })
    .addCase(fetchUser.rejected, (state, action) => {
      state.loading = false;
      state.error = action.payload as string;
    });
}

Выводы

Для импорта слайса в Redux стор: создайте слайс с createSlice, экспортируйте reducer по умолчанию, импортируйте его в configureStore с уникальным ключом. Redux Toolkit значительно упростил работу с Redux, исключив необходимость в action creators и типовом коде. Используйте типизацию TypeScript для надёжности.

Как импортировать слайс в Redux-стор? | PrepBro