В React-компонентах легко управлять локальным состоянием с помощью useState или useReducer. Но что, если нам нужно делиться состоянием между несколькими компонентами, часто находящимися в разных частях дерева? Вот здесь начинается настоящий вызов, который решается с помощью управления глобальным состоянием.

Сегодня мы разберём, зачем нужен Redux, его основные принципы, а также познакомимся с современными альтернативами. На практике создадим минимальное приложение для управления списком покупок с помощью Redux Toolkit.

Зачем нужен Redux?

Redux — это библиотека для управления состоянием приложения. Она помогает хранить глобальные данные, которые могут использоваться несколькими компонентами, и предоставляет удобные инструменты для работы с ними.

Проблемы, которые решает Redux:

  • Пропс-дриллинг: Передача данных через несколько уровней компонентов.
  • Сложность синхронизации состояния: Когда одно и то же состояние изменяется из разных частей приложения.
  • Трудности с отладкой: Redux делает изменения состояния прозрачными и предсказуемыми.

Основные принципы Redux:

  • Единый источник правды: Всё состояние приложения хранится в одном объекте — store.
  • Только для чтения: Состояние нельзя изменить напрямую. Единственный способ — отправить действие (action), описывающее изменение.
  • Чистые функции: Логика изменения состояния определяется редьюсерами — функциями, которые принимают текущее состояние и действие, а возвращают новое состояние.

Современные альтернативы Redux

Redux долгое время был стандартом для управления глобальным состоянием, но с развитием React появились более лёгкие и удобные решения. Вот некоторые из них:

Zustand

Минималистичная библиотека для управления состоянием.

Простая и понятная API: состояние создаётся через функции, без редьюсеров и экшенов.

Идеально для небольших и средних приложений.

Пример

import create from 'zustand';

const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}));

Jotai

Библиотека атомарного состояния. Каждая часть состояния хранится в атоме, который можно подключать к компонентам.

Прямой доступ к состоянию, без промежуточных слоёв.

Пример

import { atom, useAtom } from 'jotai';

const countAtom = atom(0);

function Counter() {
  const [count, setCount] = useAtom(countAtom);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

React Query

Решение для работы с данными из API. Управляет кэшированием, синхронизацией и состоянием загрузки данных.

Лучше всего подходит для управления серверным состоянием.

Пример

import { useQuery } from 'react-query';

function Users() {
  const { data, isLoading } = useQuery('users', fetchUsers);
  if (isLoading) return <p>Загрузка...</p>;
  return <ul>{data.map((user) => <li key={user.id}>{user.name}</li>)}</ul>;
}

Почему всё ещё стоит изучать Redux?

  • Мощность и гибкость: Подходит для сложных приложений.
  • Прозрачность: Легко отследить, что изменило состояние, благодаря экшенам и редьюсерам.
  • Экосистема: Большое сообщество, плагины и поддержка.

С Redux Toolkit настройка и использование Redux стали проще, устранив многие недостатки оригинального Redux.

Практика: список покупок с Redux Toolkit

Создадим приложение, где пользователь может:

  • Добавлять товары в список покупок.
  • Удалять товары из списка.
  • Просматривать текущий список.

Шаг 1: Установка Redux Toolkit

Убедитесь, что Redux Toolkit установлен:

npm install @reduxjs/toolkit react-redux

Шаг 2: Настройка Redux

Создаём файл store.js для хранения состояния:

import { configureStore, createSlice } from '@reduxjs/toolkit';

// Создаём slice (редьюсер и экшены)
const shoppingListSlice = createSlice({
  name: 'shoppingList',
  initialState: [],
  reducers: {
    addItem: (state, action) => {
      state.push(action.payload);
    },
    removeItem: (state, action) => {
      return state.filter((item, index) => index !== action.payload);
    },
  },
});

export const { addItem, removeItem } = shoppingListSlice.actions;

const store = configureStore({
  reducer: {
    shoppingList: shoppingListSlice.reducer,
  },
});

export default store;

Шаг 3: Подключение Redux к React

Оборачиваем приложение в Provider:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

Шаг 4: Компоненты приложения

Создаём компонент для списка покупок:

Компонент списка:

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { removeItem } from './store';

function ShoppingList() {
  const items = useSelector((state) => state.shoppingList);
  const dispatch = useDispatch();

  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>
          {item}{' '}
          <button onClick={() => dispatch(removeItem(index))}>
            Удалить
          </button>
        </li>
      ))}
    </ul>
  );
}

export default ShoppingList;

Компонент добавления:

import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { addItem } from './store';

function AddItem() {
  const [text, setText] = useState('');
  const dispatch = useDispatch();

  const handleSubmit = (e) => {
    e.preventDefault();
    if (text.trim()) {
      dispatch(addItem(text));
      setText('');
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="Добавьте товар"
      />
      <button type="submit">Добавить</button>
    </form>
  );
}

export default AddItem;

Шаг 5: Объединяем компоненты

В App.jsx подключаем все компоненты:

import React from 'react';
import ShoppingList from './ShoppingList';
import AddItem from './AddItem';

function App() {
  return (
    <div style={{ padding: '20px', fontFamily: 'Arial, sans-serif' }}>
      <h1>Список покупок</h1>
      <AddItem />
      <ShoppingList />
    </div>
  );
}

export default App;

Шаг 6: Запускаем проект

Запустите приложение:

npm start

Добавляйте товары, удаляйте их, и ваш список будет обновляться в реальном времени.

Итоги

Сегодня мы разобрали:

  • Зачем нужен Redux: Для управления глобальным состоянием в сложных приложениях.
  • Современные альтернативы: Zustand, Jotai, React Query — для разных сценариев.
  • На практике создали приложение с Redux Toolkit.

Redux или альтернативы?

  • Выберите Redux для сложных приложений.
  • Рассмотрите Zustand или Jotai для лёгких и средних задач.
  • Используйте React Query для работы с серверными данными.

Теперь вы можете уверенно выбирать инструменты для управления состоянием в ваших проектах.

 

Комментарии

0

Без регистрации и смс