← Назад к вопросам
Как достать состояние из RTK reducer?
2.0 Middle🔥 131 комментариев
#State Management
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Получение состояния из RTK (Redux Toolkit) Reducer
Вопрос о работе с Redux Toolkit. Покажу различные способы получения состояния из редьюсера.
Что такое Redux Toolkit?
RTK - это современный способ работы с Redux. Упрощает создание:
- Reducers (редьюсеры)
- Actions (действия)
- Store (хранилище)
- Selectors (селекторы)
1. Создание slice редьюсера
Сначала создаем slice с состоянием:
import { createSlice } from '@reduxjs/toolkit';
const userSlice = createSlice({
name: 'user',
initialState: {
profile: {
id: 1,
name: 'John',
email: 'john@example.com'
},
isLoading: false,
error: null
},
reducers: {
setUser: (state, action) => {
state.profile = action.payload;
},
setLoading: (state, action) => {
state.isLoading = action.payload;
}
}
});
export const { setUser, setLoading } = userSlice.actions;
export default userSlice.reducer;
2. Настройка Store
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './userSlice';
import postsReducer from './postsSlice';
export const store = configureStore({
reducer: {
user: userReducer,
posts: postsReducer
}
});
3. Получение состояния - основные способы
Способ 1: useSelector (основной в функциональных компонентах)
import { useSelector } from 'react-redux';
function UserProfile() {
// Получаем весь объект user
const user = useSelector(state => state.user);
// Получаем только profile
const profile = useSelector(state => state.user.profile);
// Получаем только name
const name = useSelector(state => state.user.profile.name);
return <h1>{name}</h1>;
}
Способ 2: useSelector с селектором (лучшая практика)
// Сначала создаем селекторы
export const selectUser = (state) => state.user;
export const selectProfile = (state) => state.user.profile;
export const selectUserName = (state) => state.user.profile.name;
export const selectIsLoading = (state) => state.user.isLoading;
// Потом используем в компонентах
function UserProfile() {
const profile = useSelector(selectProfile);
const isLoading = useSelector(selectIsLoading);
if (isLoading) return <div>Загрузка...</div>;
return <h1>{profile.name}</h1>;
}
Способ 3: Использование reselect для мемоизации
import { createSelector } from '@reduxjs/toolkit';
// Мемоизируем селектор (вызывается только если значение изменилось)
export const selectUserInitials = createSelector(
state => state.user.profile,
profile => profile.name
.split(' ')
.map(n => n[0])
.join('')
);
export const selectUserFullInfo = createSelector(
state => state.user.profile,
state => state.user.isLoading,
(profile, isLoading) => ({
...profile,
isLoading
})
);
// В компоненте
function UserCard() {
const initials = useSelector(selectUserInitials);
const fullInfo = useSelector(selectUserFullInfo);
return (
<div>
<span>{initials}</span>
<p>{fullInfo.name}</p>
</div>
);
}
4. Получение в классовых компонентах
Способ 1: connect (старый стиль, но еще используется)
import { connect } from 'react-redux';
class UserProfile extends React.Component {
render() {
const { user, profile, isLoading } = this.props;
return <h1>{profile.name}</h1>;
}
}
// Маппим состояние на props
const mapStateToProps = (state) => ({
user: state.user,
profile: state.user.profile,
isLoading: state.user.isLoading
});
export default connect(mapStateToProps)(UserProfile);
Способ 2: useSelector в функциональном компоненте (рекомендуется)
import { useSelector } from 'react-redux';
import { selectProfile, selectIsLoading } from './userSlice';
function UserProfile() {
const profile = useSelector(selectProfile);
const isLoading = useSelector(selectIsLoading);
return (
<div>
{isLoading ? <p>Загрузка...</p> : <h1>{profile.name}</h1>}
</div>
);
}
5. Получение с фильтрацией (createSelector)
import { createSelector } from '@reduxjs/toolkit';
// Создаем селектор для постов пользователя
export const selectUserPosts = createSelector(
state => state.posts.items,
state => state.user.profile.id,
(posts, userId) => posts.filter(post => post.userId === userId)
);
function UserPosts() {
const posts = useSelector(selectUserPosts);
return (
<ul>
{posts.map(post => <li key={post.id}>{post.title}</li>)}
</ul>
);
}
6. Оптимизация: избегай глубокого поиска в каждом рендере
// ПЛОХО: этот селектор создает новый объект каждый раз
function BadExample() {
const user = useSelector(state => ({
name: state.user.profile.name,
email: state.user.profile.email
}));
}
// ХОРОШО: используем мемоизированный селектор
export const selectUserInfo = createSelector(
state => state.user.profile,
profile => ({
name: profile.name,
email: profile.email
})
);
function GoodExample() {
const user = useSelector(selectUserInfo);
}
7. Асинхронные операции (createAsyncThunk)
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
// Создаем асинхронное действие
export const fetchUser = createAsyncThunk(
'user/fetchUser',
async (userId) => {
const response = await fetch(`/api/users/${userId}`);
return response.json();
}
);
const userSlice = createSlice({
name: 'user',
initialState: {
profile: null,
loading: false,
error: null
},
extraReducers: (builder) => {
builder
.addCase(fetchUser.pending, (state) => {
state.loading = true;
})
.addCase(fetchUser.fulfilled, (state, action) => {
state.loading = false;
state.profile = action.payload;
})
.addCase(fetchUser.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message;
});
}
});
// Использование в компоненте
function UserLoader() {
const dispatch = useDispatch();
const { profile, loading, error } = useSelector(state => state.user);
useEffect(() => {
dispatch(fetchUser(1));
}, [dispatch]);
if (loading) return <p>Загрузка...</p>;
if (error) return <p>Ошибка: {error}</p>;
return <h1>{profile?.name}</h1>;
}
8. Структурированный пример (лучшая практика)
// userSlice.js
import { createSlice, createSelector } from '@reduxjs/toolkit';
const userSlice = createSlice({
name: 'user',
initialState: {
profile: null,
preferences: {},
isLoading: false
},
reducers: {
setProfile: (state, action) => {
state.profile = action.payload;
}
}
});
// Селекторы (экспортируем)
export const selectUser = (state) => state.user;
export const selectProfile = (state) => state.user.profile;
export const selectIsLoading = (state) => state.user.isLoading;
export const selectUserDisplayName = createSelector(
selectProfile,
profile => profile?.name || 'Anonymous'
);
export default userSlice.reducer;
// UserProfile.jsx
import { useSelector } from 'react-redux';
import { selectProfile, selectUserDisplayName, selectIsLoading } from './userSlice';
function UserProfile() {
const profile = useSelector(selectProfile);
const displayName = useSelector(selectUserDisplayName);
const isLoading = useSelector(selectIsLoading);
return (
<div>
{isLoading && <p>Загрузка...</p>}
{profile && (
<div>
<h1>{displayName}</h1>
<p>{profile.email}</p>
</div>
)}
</div>
);
}
Выводы
Как получить состояние из RTK reducer:
- useSelector - основной хук для функциональных компонентов
- Создавай селекторы - храни их в том же файле slice
- Используй createSelector - для мемоизации и производительности
- Избегай анонимных селекторов - создавай именованные функции
- Логика фильтрации в селекторах - не в компонентах
Современный Redux Toolkit значительно упростил работу с состоянием по сравнению с обычным Redux.