Вспоминаем срезы (slices) в Redux Toolkit
Если говорить метафорически, то глобальное состояние нашего приложения можно представить как большой пирог, куски которого — это различные куски логики и данных: например, состояние аутентификации, список продуктов в корзине, настройки приложения. Каждый такой кусок управляется отдельным срезом (slice). Redux Toolkit упрощает управление этими "кусочками", предоставляя удобный API для их создания.
С помощью функции createSlice мы можем:
- Задать начальное состояние.
- Определить редьюсеры (reducers) — функции, которые изменяют состояние.
- Автоматически сгенерировать экшены (actions) для каждого редьюсера.
Круто, правда? Теперь погнали писать код!
Создание среза
Прежде чем погрузиться в код, давайте подумаем о структуре нашего проекта. Обычно для удобства мы создаем отдельные папки для управления состоянием. Например:
src/
redux/
slices/
authSlice.ts
settingsSlice.ts
store.ts
Таким образом, каждый срез будет находиться в папке slices, а файл store.ts будет объединять их в единое хранилище.
Пример создания authSlice (срез для управления аутентификацией)
// src/redux/slices/authSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
// Типизация состояния
interface AuthState {
isAuthenticated: boolean;
user: string | null;
}
// Начальное состояние
const initialState: AuthState = {
isAuthenticated: false,
user: null,
};
// Создание среза
const authSlice = createSlice({
name: 'auth', // Уникальное имя среза (slice)
initialState,
reducers: {
login(state, action: PayloadAction<string>) {
// Устанавливаем пользователя как аутентифицированного
state.isAuthenticated = true;
state.user = action.payload; // Сохраняем имя пользователя
},
logout(state) {
// Сбрасываем состояние пользователя при выходе
state.isAuthenticated = false;
state.user = null;
},
},
});
// Экспортируем действия и редьюсер
export const { login, logout } = authSlice.actions;
export default authSlice.reducer;
Пояснение коду
Типизация состояния: мы описали интерфейс
AuthState, который представляет состояние среза. Это помогает нам избежать ошибок при работе с состоянием.Начальное состояние: задали
initialState, которое будет использоваться при начальной загрузке приложения.Редьюсеры:
login: обновляет состояние, устанавливая флаг аутентификации вtrueи добавляя имя пользователя.logout: сбрасывает состояние пользователя.
Генерация экшенов: используя
createSlice, мы автоматически получаем экшеныloginиlogout.
Настройка Store
Теперь, когда у нас есть первый срез, мы можем связать его со store. В Redux store — это место, где живет все состояние нашего приложения. Создадим его следующим образом:
// src/redux/store.ts
import { configureStore } from '@reduxjs/toolkit';
import authReducer from './slices/authSlice';
// Создание Store
const store = configureStore({
reducer: {
auth: authReducer, // Подключение authSlice к store
},
});
// Типизация корневого состояния
export type RootState = ReturnType<typeof store.getState>;
// Экспортируем store
export default store;
Пояснение
configureStore: это метод изRedux Toolkit, который упрощает настройку хранилища. Он автоматически подключает DevTools и другие полезные вещи.Подключение редьюсеров: мы добавили
authReducerв нашstore, связав его с ключомauth.Типизация
RootState: это важно дляuseSelector(мы скоро это увидим).
Подключаем Store к приложению
Чтобы компоненты React могли взаимодействовать с нашим store, нужно обернуть корневой компонент в провайдер Provider из библиотеки react-redux. Это создаст контекст, в котором наш store будет доступен.
// App.tsx
import React from 'react';
import { Provider } from 'react-redux';
import store from './redux/store';
import MainScreen from './screens/MainScreen';
const App = () => {
return (
<Provider store={store}>
<MainScreen />
</Provider>
);
};
export default App;
Теперь состояние доступно во всем приложении.
Добавим функционал логина
Создадим простой экран, где пользователь может ввести свое имя и войти:
// src/screens/MainScreen.tsx
import React, { useState } from 'react';
import { View, Text, TextInput, Button, StyleSheet } from 'react-native';
import { useSelector, useDispatch } from 'react-redux';
import { login, logout } from '../redux/slices/authSlice';
import { RootState } from '../redux/store';
const MainScreen = () => {
const [username, setUsername] = useState('');
const isAuthenticated = useSelector((state: RootState) => state.auth.isAuthenticated);
const user = useSelector((state: RootState) => state.auth.user);
const dispatch = useDispatch();
const handleLogin = () => {
dispatch(login(username)); // Отправляем действие login
setUsername(''); // Очищаем поле ввода
};
const handleLogout = () => {
dispatch(logout()); // Отправляем действие logout
};
return (
<View style={styles.container}>
{isAuthenticated ? (
<View>
<Text style={styles.text}>Добро пожаловать, {user}!</Text>
<Button title="Выйти" onPress={handleLogout} />
</View>
) : (
<View>
<TextInput
style={styles.input}
value={username}
onChangeText={setUsername}
placeholder="Введите имя"
/>
<Button title="Войти" onPress={handleLogin} />
</View>
)}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
text: {
fontSize: 20,
marginBottom: 10,
},
input: {
borderWidth: 1,
borderColor: '#ccc',
padding: 10,
width: '80%',
marginBottom: 10,
},
});
export default MainScreen;
Как это работает?
useSelectorиuseDispatch: мы подключили компонент к состоянию через хуки.useSelectorпозволяет получить данные изstore, аuseDispatchотправляет экшены.Динамическая отрисовка: в зависимости от состояния
isAuthenticatedмы показываем форму входа или приветственное сообщение.Состояние управляется через Redux: весь функционал логина/выхода завязан на глобальном состоянии, так что его могут использовать и другие компоненты.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ