React-Redux — это популярная библиотека управления состоянием, которая помогает эффективно управлять состоянием приложений на React. Это незаменимый инструмент в экосистеме React, позволяющий легко обрабатывать сложную логику состояния и поток данных в больших приложениях. React-Redux устанавливает связь между Redux store и React-компонентами, обеспечивая бесшовное взаимодействие между ними.
Прежде чем перейти к React-Redux, важно понять, что такое Redux и зачем он нужен.
Что такое Redux?
Redux — это предсказуемый контейнер состояния для JavaScript приложений. Он помогает централизованно управлять состоянием приложения, что упрощает поддержку и отладку, особенно по мере роста сложности.
Redux основан на трёх основных принципах:
- Единый источник правды (Single Source of Truth): всё состояние приложения хранится в одном JavaScript-объекте, называемом store.
- Состояние доступно только для чтения (State is Read-Only): изменить состояние можно только путём отправки action — объекта, описывающего изменение.
- Изменения выполняются с помощью чистых функций (Changes are Made with Pure Functions): трансформации состояния выполняют reducers — чистые функции, которые принимают предыдущее состояние и action, а возвращают новое состояние.
Зачем использовать React-Redux?
React-Redux — официальная библиотека для подключения Redux к React. Ниже перечислены причины, по которым разработчики выбирают React-Redux:
- Упрощение управления состоянием: React-Redux организует обработку изменений состояния, позволяя централизованно контролировать их, что облегчает отслеживание изменений во всём приложении.
- Предсказуемый поток состояния: Redux гарантирует, что состояние меняется только через действия, обрабатываемые редьюсерами, что делает процесс прозрачным и удобным для отладки.
- Разделение UI-компонентов и логики состояния: React-Redux позволяет компонентам сосредоточиться на отображении UI, тогда как Redux управляет состоянием.
- Упрощённая отладка: благодаря поддержке инструментов, таких как Redux DevTools, вы можете просматривать, логировать и возвращать изменения состояния, что значительно ускоряет процесс отладки.
- Оптимизация производительности: React-Redux применяет shallow equality checks [поверхностное сравнение], чтобы обновлять компоненты только при действительно изменившемся состоянии, предотвращая лишние ререндеры.
Основные концепции React-Redux
Для эффективного использования React-Redux необходимо знать ключевые понятия:
1. Store
Store — централизованный объект, содержащий состояние приложения. Изменять состояние можно только через store.
2. Actions
Action — простой JavaScript-объект, описывающий изменение состояния. Он обязательно содержит свойство type и при необходимости — payload.
const incrementAction = {
type: 'INCREMENT',
payload: 1
};
3. Reducers
Reducer — чистая функция, описывающая, как изменяется состояние в ответ на действие. Она принимает текущее состояние и action, возвращая новое состояние.
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + action.payload;
case 'DECREMENT':
return state - action.payload;
default:
return state;
}
};
4. Dispatch
Функция dispatch используется для отправки действий (actions) в Redux store, инициируя работу редьюсера для обновления состояния.
store.dispatch(incrementAction);
5. Selectors
Selector — функция, которая извлекает определённые данные из состояния Redux store. Это упрощает доступ к состоянию и способствует поддерживаемости кода.
const selectCount = (state) => state.count;
6. Provider
Компонент Provider предоставляет Redux store всем компонентам приложения. Его следует обернуть вокруг всего приложения, чтобы обеспечить доступ к store из любого компонента.
import { Provider } from 'react-redux';
<Provider store={store}>
<App />
</Provider>;
7. connect()
Функция connect() из React-Redux предназначена для подключения React-компонентов к Redux store. Она позволяет компонентам получать доступ к состоянию и отправлять действия.
import { connect } from 'react-redux';
const Counter = ({ count, increment }) => (
<div>
<h1>{count}</h1>
<button onClick={increment}>Increment</button>
</div>
);
const mapStateToProps = (state) => ({
count: state.count
});
const mapDispatchToProps = (dispatch) => ({
increment: () => dispatch({ type: 'INCREMENT', payload: 1 })
});
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
Как работает React-Redux
React-Redux связывает React-компоненты и Redux store, обеспечивая комфортное управление состоянием во всем приложении. Поясним процесс по шагам:
1. Создание Store
Redux store содержит всё состояние приложения. Его создают с помощью функции createStore() и инициализируют редьюсером — функцией, управляющей изменениями состояния.
const store = createStore(counterReducer);
2. Отправка Actions
Actions — простые объекты, описывающие изменения состояния. Они отправляются в Redux с помощью dispatch, уведомляя об изменениях.
store.dispatch({ type: 'INCREMENT', payload: 1 });
3. Редьюсеры обновляют состояние
Reducer обновляет состояние в зависимости от типа действия. Он получает текущее состояние и action, возвращая новое состояние.
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT': return state + action.payload;
default: return state;
}
};
4. Подключение компонентов с connect()
Функция connect() позволяет связать React-компоненты с Redux store для доступа к состоянию и отправки действий.
const mapStateToProps = (state) => ({ count: state });
const mapDispatchToProps = (dispatch) => ({
increment: () => dispatch({ type: 'INCREMENT', payload: 1 })
});
5. Использование Provider для предоставления доступа к Store
Компонент Provider делает store доступным всем компонентам приложения.
<Provider store={store}><App /></Provider>
6. Ререндеры и реактивность
React-Redux гарантирует, что повторный рендер затрагивает только те компоненты, которые зависят от обновлённого состояния, что оптимизирует производительность приложения.
Шаги по внедрению React-Redux
Шаг 1: Создание проекта
Сначала создайте новое React-приложение с помощью create-react-app:
npx create-react-app react-redux-counter
cd react-redux-counter
Затем установите redux и react-redux:
npm install redux react-redux
Структура папок
Зависимости
"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^9.1.2",
"react-scripts": "5.0.1",
"redux": "^5.0.1",
"web-vitals": "^2.1.4"
}
Шаг 2: Определите типы actions
Необходимо задать типы действий, которые будут обновлять состояние.
// src/redux/actionTypes.js
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
Шаг 3: Создайте action creators
Action creators — это функции, возвращающие объекты actions.
// src/redux/actions.js
import { INCREMENT, DECREMENT } from "./actionTypes";
export const increment = () => ({
type: INCREMENT,
});
export const decrement = () => ({
type: DECREMENT,
});
Шаг 4: Напишите редьюсер
Редьюсер описывает, как изменяется состояние приложения в ответ на действия. Он принимает текущее состояние и action и возвращает обновлённое состояние.
// src/redux/reducer.js
import { INCREMENT, DECREMENT } from "./actionTypes";
const initialState = {
count: 0,
};
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case INCREMENT:
return { ...state, count: state.count + 1 };
case DECREMENT:
return { ...state, count: state.count - 1 };
default:
return state;
}
};
export default counterReducer;
Шаг 5: Создайте Redux store
Создайте Redux store с помощью функции createStore.
// src/redux/store.js
import { createStore } from 'redux';
import counterReducer from './reducer';
const store = createStore(counterReducer);
export default store;
Шаг 6: Оберните приложение в Redux Provider
Оберните всё приложение компонентом Provider, чтобы обеспечить доступ к store во всех компонентах.
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './redux/store';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
Шаг 7: Создайте главный компонент App
// src/App.js
import React from "react";
import Counter from "./components/Counter";
function App() {
return (
<div className="App">
<h1>React-Redux Counter App</h1>
<Counter />
</div>
);
}
export default App;
Шаг 8: Создайте компонент Counter
// src/components/Counter.js
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { increment, decrement } from "../redux/actions";
const Counter = () => {
const count = useSelector((state) => state.count);
const dispatch = useDispatch();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch(increment())}>Increment</button>
<button onClick={() => dispatch(decrement())}>Decrement</button>
</div>
);
};
export default Counter;
Для запуска приложения выполните команду:
npm start
Вывод
Заключение
В этой статье мы рассмотрели React-Redux, который упрощает управление состоянием в React, централизуя его в Redux store. Используя Provider, connect() и хуки React-Redux — useSelector и useDispatch, компоненты React получают удобный доступ к глобальному состоянию и могут его обновлять. React-Redux помогает повысить предсказуемость состояния, производительность и удобство поддержки, особенно в больших приложениях.
🔑 Ключевые моменты:
- Redux управляет состоянием через единственный store, обеспечивая предсказуемость и централизованность.
- React-Redux соединяет Redux c React, упрощая доступ к состоянию и отправку действий.
- Компоненты React отделены от логики управления состоянием благодаря React-Redux.
- Хуки useSelector и useDispatch заменяют connect() и делают код легче для восприятия.
- Поддержка инструментов отладки и оптимизации ререндеров повышает качество и производительность приложений.