Підключення до React (React-Redux)
Підключення до React (React-Redux)
Сам по собі Redux нічого не знає про React. Щоб "пожружити" їх, нам потрібна офіційна бібліотека-прошарок: React Redux.
npm install react-redux
Вона надає нам два ключові інструменти:
<Provider>— компонент, який робить стор доступним для всього додатку.- Hooks (
useSelector,useDispatch) — для взаємодії компонентів зі стором.
Крок 1: Provider
Ми маємо обгорнути наш кореневий компонент (зазвичай <App>) у <Provider> і передати йому наш створений store.
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store'; // Наш store з попередніх уроків
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
Під капотом Provider використовує React Context, тому нам не потрібно передавати пропси вручну через всі компоненти.
Крок 2: Читання даних (useSelector)
Щоб отримати дані зі стору в компоненті, використовуємо хук useSelector.
import { useSelector } from 'react-redux';
const CounterDisplay = () => {
// Функція-селектор приймає весь state і повертає потрібну частину
const count = useSelector(state => state.value);
return <h1>Поточний рахунок: {count}</h1>;
};
Особливості useSelector:
- Автоматична підписка: Компонент автоматично підписується на зміни стору.
- Розумний ре-рендер: Якщо
state.valueзмінилося, компонент перемалюється. Якщо змінилося щось інше (наприклад,state.user), компонент не буде перемальовуватися (за умови, що селектор повертає те саме значення). - Порівняння посилань:
useSelectorвикористовує суворе порівняння (===).
Обережно з об'єктами! Якщо ваш селектор повертає новий об'єкт кожного разу, компонент буде ре-рендеритися постійно, навіть якщо дані не змінилися.
// ❌ Погано: створює новий об'єкт { a, b } при кожному виклику
const { a, b } = useSelector(state => ({ a: state.a, b: state.b }));
// ✅ Добре: викликати useSelector кілька разів
const a = useSelector(state => state.a);
const b = useSelector(state => state.b);
Крок 3: Зміна даних (useDispatch)
Щоб відправити action, використовуємо хук useDispatch.
import { useDispatch } from 'react-redux';
const CounterControls = () => {
const dispatch = useDispatch();
return (
<div>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>+</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>-</button>
</div>
);
};
Історична довідка: connect()
У старих туторіалах (до 2019 року) ви можете побачити функцію connect та mapStateToProps. Це старий спосіб (Higher-Order Component), який використовувався в класових компонентах.
// Legacy Style 👴
class Counter extends React.Component { ... }
const mapStateToProps = state => ({ count: state.value });
const mapDispatchToProps = { increment };
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
Сьогодні використання Hooks є стандартом. connect все ще працює, але використовувати його в новому коді не рекомендується.
Ми навчилися працювати з синхронними даними. Але що робити, коли нам потрібно завантажити дані з сервера? Redux "з коробки" не вміє працювати з асинхронністю. Нам потрібен Middleware.