🚀 Веб-разработка с нуля: Урок 25 — State-менеджмент с Redux Toolkit
Привет, React-разработчики! 👨💻👩💻
Сегодня выведем управление состоянием на профессиональный уровень — внедрим Redux Toolkit в наше To-Do приложение!
### 🔥 Зачем Redux Toolkit?
- Упрощенная настройка хранилища
- Встроенная иммутабельность
- DevTools для отладки
- Оптимизированные перерисовки
### 🛠 Настройка за 4 шага
1️⃣ Устанавливаем зависимости:
2️⃣ Создаем слайс задач (
3️⃣ Настраиваем хранилище (
4️⃣ Подключаем к React (
### 💡 Используем в компонентах
### 🚀 Что это даёт?
- Централизованное управление состоянием
- Предсказуемость изменений
- Лёгкую масштабируемость
- Возможность time-travel дебаггинга
### 📌 Практическое задание
1. Реализуйте удаление задач
2. Добавьте фильтрацию (все/активные/выполненные)
3. Подключите сохранение в localStorage
👉 В следующем уроке:
Асинхронные действия с Redux Thunk!
💬 Какие state-менеджеры пробовали до этого?
Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
#Redux #React #TypeScript #ВебРазработка
Привет, React-разработчики! 👨💻👩💻
Сегодня выведем управление состоянием на профессиональный уровень — внедрим Redux Toolkit в наше To-Do приложение!
### 🔥 Зачем Redux Toolkit?
- Упрощенная настройка хранилища
- Встроенная иммутабельность
- DevTools для отладки
- Оптимизированные перерисовки
### 🛠 Настройка за 4 шага
1️⃣ Устанавливаем зависимости:
npm install @reduxjs/toolkit react-redux
2️⃣ Создаем слайс задач (
features/tasks/tasksSlice.ts): import { createSlice, PayloadAction } from '@reduxjs/toolkit';
interface Task {
id: string;
text: string;
completed: boolean;
}
const initialState: Task[] = [];
export const tasksSlice = createSlice({
name: 'tasks',
initialState,
reducers: {
addTask: (state, action: PayloadAction<string>) => {
state.push({
id: Date.now().toString(),
text: action.payload,
completed: false
});
},
toggleTask: (state, action: PayloadAction<string>) => {
const task = state.find(t => t.id === action.payload);
if (task) task.completed = !task.completed;
}
}
});
export const { addTask, toggleTask } = tasksSlice.actions;
export default tasksSlice.reducer;3️⃣ Настраиваем хранилище (
app/store.ts): import { configureStore } from '@reduxjs/toolkit';
import tasksReducer from '../features/tasks/tasksSlice';
export const store = configureStore({
reducer: {
tasks: tasksReducer
}
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;4️⃣ Подключаем к React (
main.tsx): import { Provider } from 'react-redux';
import { store } from './app/store';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);### 💡 Используем в компонентах
import { useAppDispatch, useAppSelector } from '../app/hooks';
import { addTask, toggleTask } from './tasksSlice';
export const TaskList = () => {
const tasks = useAppSelector(state => state.tasks);
const dispatch = useAppDispatch();
const handleAdd = (text: string) => dispatch(addTask(text));
const handleToggle = (id: string) => dispatch(toggleTask(id));
return (
/* JSX с использованием tasks и handlers */
);
};### 🚀 Что это даёт?
- Централизованное управление состоянием
- Предсказуемость изменений
- Лёгкую масштабируемость
- Возможность time-travel дебаггинга
### 📌 Практическое задание
1. Реализуйте удаление задач
2. Добавьте фильтрацию (все/активные/выполненные)
3. Подключите сохранение в localStorage
👉 В следующем уроке:
Асинхронные действия с Redux Thunk!
💬 Какие state-менеджеры пробовали до этого?
Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
#Redux #React #TypeScript #ВебРазработка
🚀 Веб-разработка с нуля: Урок 26 — Асинхронные действия с Redux Thunk
Привет, покорители state-менеджмента! 👨💻👩💻
Сегодня научим наш To-Do List работать с API и асинхронными операциями через Redux Thunk!
### 🔥 Зачем нужен Thunk?
• Обработка асинхронных запросов
• Инкапсуляция бизнес-логики
• Работа с побочными эффектами
### 🛠 Настройка асинхронного слайса
1️⃣ Добавляем API-слой (
2️⃣ Модернизируем слайс (
### 💡 Использование в компонентах
### 🚀 5 преимуществ подхода
1. Разделение ответственности (UI ≠ бизнес-логика)
2. Автоматические состояния загрузки/ошибок
3. Кеширование данных
4. Оптимистичные обновления UI
5. Легкое тестирование
### 📌 Практическое задание
1. Реализуйте удаление задач через API
2. Добавьте обработку ошибок
3. Внедрите оптимистичное обновление для toggle
👉 В следующем уроке:
Тестирование Redux-приложения с Jest!
💬 Какую логику вы вынесли бы в thunks?
Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
#Redux #Thunk #React #Асинхронность
Привет, покорители state-менеджмента! 👨💻👩💻
Сегодня научим наш To-Do List работать с API и асинхронными операциями через Redux Thunk!
### 🔥 Зачем нужен Thunk?
• Обработка асинхронных запросов
• Инкапсуляция бизнес-логики
• Работа с побочными эффектами
### 🛠 Настройка асинхронного слайса
1️⃣ Добавляем API-слой (
features/tasks/tasksAPI.ts): import { Task } from './tasksSlice';
const API_URL = 'https://your-api.com/tasks';
export const fetchTasks = async (): Promise<Task[]> => {
const response = await fetch(API_URL);
return await response.json();
};
export const saveTask = async (task: Task): Promise<Task> => {
const response = await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(task)
});
return await response.json();
};2️⃣ Модернизируем слайс (
tasksSlice.ts): import { createAsyncThunk } from '@reduxjs/toolkit';
import { fetchTasks, saveTask } from './tasksAPI';
export const loadTasks = createAsyncThunk('tasks/load', async () => {
return await fetchTasks();
});
export const addTaskAsync = createAsyncThunk(
'tasks/add',
async (text: string) => {
const newTask = { text, completed: false };
return await saveTask(newTask);
}
);
const tasksSlice = createSlice({
// ...существующие reducers
extraReducers: (builder) => {
builder
.addCase(loadTasks.fulfilled, (state, action) => {
return action.payload;
})
.addCase(addTaskAsync.fulfilled, (state, action) => {
state.push(action.payload);
});
}
});### 💡 Использование в компонентах
import { loadTasks, addTaskAsync } from './tasksSlice';
export const TaskList = () => {
const dispatch = useAppDispatch();
const { loading, error } = useAppSelector(state => state.tasks.meta);
useEffect(() => {
dispatch(loadTasks());
}, []);
const handleAdd = (text: string) => {
dispatch(addTaskAsync(text));
};
if (loading) return <Spinner />;
if (error) return <ErrorAlert message={error} />;
return ( /* ... */ );
};### 🚀 5 преимуществ подхода
1. Разделение ответственности (UI ≠ бизнес-логика)
2. Автоматические состояния загрузки/ошибок
3. Кеширование данных
4. Оптимистичные обновления UI
5. Легкое тестирование
### 📌 Практическое задание
1. Реализуйте удаление задач через API
2. Добавьте обработку ошибок
3. Внедрите оптимистичное обновление для toggle
👉 В следующем уроке:
Тестирование Redux-приложения с Jest!
💬 Какую логику вы вынесли бы в thunks?
Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
#Redux #Thunk #React #Асинхронность
🚀 Веб-разработка с нуля: Урок 27 — Тестирование Redux с Jest
Привет, будущие эксперты качества кода! 👨💻👩💻
Сегодня научимся писать тесты для Redux-приложения, чтобы ловить баги до того, как их увидят пользователи!
### 🔥 Зачем тестировать Redux?
• Проверка корректности редьюсеров
• Контроль бизнес-логики
• Предотвращение регрессий
### 🛠 Настраиваем тестовое окружение
1️⃣ Устанавливаем зависимости:
2️⃣ Конфиг
### 💡 Тестируем редьюсер (
### 🧪 Тестируем асинхронные thunks
### 🚀 Тестируем компоненты (
### 📌 Практическое задание
1. Напишите тест для неудачного сценария загрузки задач
2. Протестируйте компонент с заполненным списком
3. Добавьте snapshot-тест для редьюсера
👉 В следующем уроке:
CI/CD — Настраиваем автоматические тесты!
💬 Какие части вашего приложения нужно покрыть тестами в первую очередь?
Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
#Jest #Testing #Redux #React #QualityAssurance
Привет, будущие эксперты качества кода! 👨💻👩💻
Сегодня научимся писать тесты для Redux-приложения, чтобы ловить баги до того, как их увидят пользователи!
### 🔥 Зачем тестировать Redux?
• Проверка корректности редьюсеров
• Контроль бизнес-логики
• Предотвращение регрессий
### 🛠 Настраиваем тестовое окружение
1️⃣ Устанавливаем зависимости:
npm install jest @types/jest @testing-library/react redux-mock-store --save-dev
2️⃣ Конфиг
jest.config.js: module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect']
};### 💡 Тестируем редьюсер (
tasksSlice.test.ts) import tasksReducer, { addTask, toggleTask } from './tasksSlice';
describe('tasks reducer', () => {
it('should handle initial state', () => {
expect(tasksReducer(undefined, { type: 'unknown' })).toEqual([]);
});
it('should handle addTask', () => {
const actual = tasksReducer([], addTask('New task'));
expect(actual[0].text).toEqual('New task');
expect(actual[0].completed).toBe(false);
});
it('should handle toggleTask', () => {
const initialState = [{ id: '1', text: 'Test', completed: false }];
const actual = tasksReducer(initialState, toggleTask('1'));
expect(actual[0].completed).toBe(true);
});
});### 🧪 Тестируем асинхронные thunks
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { loadTasks } from './tasksSlice';
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
describe('async thunks', () => {
it('dispatches fulfilled when loadTasks succeeds', async () => {
const store = mockStore({});
await store.dispatch(loadTasks() as any);
const actions = store.getActions();
expect(actions[0].type).toEqual('tasks/load/pending');
expect(actions[1].type).toEqual('tasks/load/fulfilled');
});
});
### 🚀 Тестируем компоненты (
TaskList.test.tsx) import { render, screen } from '@testing-library/react';
import { Provider } from 'react-redux';
import { store } from '../../app/store';
import TaskList from './TaskList';
test('renders empty task list', () => {
render(
<Provider store={store}>
<TaskList />
</Provider>
);
expect(screen.getByText(/нет задач/i)).toBeInTheDocument();
});### 📌 Практическое задание
1. Напишите тест для неудачного сценария загрузки задач
2. Протестируйте компонент с заполненным списком
3. Добавьте snapshot-тест для редьюсера
👉 В следующем уроке:
CI/CD — Настраиваем автоматические тесты!
💬 Какие части вашего приложения нужно покрыть тестами в первую очередь?
Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
#Jest #Testing #Redux #React #QualityAssurance