Понимание Redux (часть 2): Создание небольшого React-приложения на базе Redux за 10 простых шагов (с фрагментами кода)

Прежде чем продолжить этот блог, я бы рекомендовал сначала ознакомиться с первой частью серии статей “Понимание Redux”, которую можно найти по этой ссылке “Понимание Redux (часть 1): Демистификация Store, Action и Reducers. Это поможет вам понять текущую статью. В блоге части 1 я попытался объяснить фундаментальные принципы/концепции Redux. Я рассказал о том, что такое Store, Actions и Reducers, что делает Redux предсказуемым, а также привел пример.

В этой статье мы попробуем создать собственное приложение на базе Redux. Мы рассмотрим, как создать Store и предоставить его приложению, написать Actions, отправлять их при взаимодействии с пользователем, сделать Reducers и обновить хранилище, прочитать хранилище из других компонентов, которые являются дочерними для App, и многое другое. Я буду предоставлять все важные фрагменты кода по ходу дела, чтобы вы могли быстро раскрутить приложение.

Чтобы дать представление о самом начале, вот что мы в итоге создадим

Мы создадим базовое приложение, в котором мы сможем добавлять и удалять товары в корзину. Мы будем управлять изменениями состояния в магазине redux и отображать информацию в пользовательском интерфейсе.

Настройка кода

1. Создайте react-приложение с помощью команды create-react-app

npx create-react-app react-app-with-redux
Войдите в полноэкранный режим Выйдите из полноэкранного режима

2. Перейдите в только что созданную папку с помощью команды

cd react-app-with-redux
Войти в полноэкранный режим Выйти из полноэкранного режима

3. Установите redux и библиотеку react-redux с помощью команд

npm install redux react-redux

Войти в полноэкранный режим Выйти из полноэкранного режима

4. Запустите приложение, используя

npm start
Войти в полноэкранный режим Выйти из полноэкранного режима

5. Создание редуктора

Сначала создайте папку внутри src с именем actionTypes и создайте в ней файл actionTypes.js. Этот файл будет содержать все действия, с которыми будет иметь дело приложение. Добавьте следующие строки в actionTypes.js

export const ADD_ITEM = "ADD_ITEM";
export const DELETE_ITEM = "DELETE_ITEM";
Войти в полноэкранный режим Выйти из полноэкранного режима

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

Далее создайте папку внутри src под названием reducers и создайте в ней новый файл с именем cartReducer.js. Этот файл будет содержать всю логику редуктора, связанную с компонентом корзины. (Примечание: Мы создадим представление/ пользовательский интерфейс на шаге 8). Добавьте следующие строки в cartReducer.js.

import { ADD_ITEM, DELETE_ITEM } from "../actionTypes/actionTypes";

const initialState = {
  numOfItems: 0,
};

export default const cartReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_ITEM:
      return {
        ...state,
        numOfItems: state.numOfItems + 1,
      };

    case DELETE_ITEM:
      return {
        ...state,
        numOfItems: state.numOfItems - 1,
      };
    default:
      return state;
  }
};

Войти в полноэкранный режим Выйти из полноэкранного режима

Как мы уже говорили в первой части этого блога, мы создали начальное состояние для приложения и присвоили его параметру по умолчанию state в функции cartReducer. Эта функция включает тип отправляемого действия, и в случае совпадения с типом действия вносит необходимые изменения в состояние и возвращает новый экземпляр обновленного состояния. Если ни один из типов действий не совпадает, то состояние возвращается как есть. Наконец, мы делаем экспорт функции cakeReducer по умолчанию, чтобы использовать ее в процессе создания магазина.

6. Создание магазина и предоставление его приложению

Создайте файл внутри src с именем store.js и создайте магазин с помощью команды

const store = createStore()
Войти в полноэкранный режим Выйти из полноэкранного режима

Добавьте следующие строки в store.js

import { createStore } from "redux";
import { cartReducer } from "./reducers/cartReducer";

const store = createStore(cartReducer);

export default store;
Войти в полноэкранный режим Выйти из полноэкранного режима

Теперь пришло время предоставить этот store компоненту App. Для этого мы используем тег <Provider>, который мы получаем из библиотеки react-redux. Мы обернем весь компонент App внутри тега <Provider>, используя следующий синтаксис.

// rest of the code ...

<Provider store={store}>
        <div>App Component</div>
        // child components of App/ other logic
</Provider>

// rest of the code ...
Войти в полноэкранный режим Выйти из полноэкранного режима

Обернув компонент App внутри тега <Provider>, все дочерние компоненты App получат доступ к store. Чтобы узнать больше, посетите часть 1 этой серии блогов.

Продолжая работу с файлом App.js, добавьте в него следующие строки.

import "./App.css";
import { Provider } from "react-redux";
import store from "./store";

function App() {
  return (
    <Provider store={store}>
      <div>App Component</div>
    </Provider>
  );
}

export default App;
Вход в полноэкранный режим Выйти из полноэкранного режима

7. Создать действия

Теперь создайте папку внутри src под названием actions и создайте в ней файл cartAction.js. Здесь мы добавим все действия, которые будут выполняться при определенном взаимодействии с пользователем. Добавьте следующие строки в cartAction.js

import { ADD_ITEM, DELETE_ITEM } from "../actionTypes/actionTypes";

const addItem = () => {
  return {
    type: ADD_ITEM,
  };
};

const deleteItem = () => {
  return {
    type: DELETE_ITEM,
  };
};

export { addItem, deleteItem };
Войти в полноэкранный режим Выйти из полноэкранного режима

В приведенном выше коде мы создали два создателя действий (чистые JS функции, возвращающие объект action) под названием addItem() и deleteItem(). Оба создателя действий возвращают объект action с определенным type. Примечание: Каждый объект action обязательно должен иметь уникальное значение type. Любые дополнительные данные, передаваемые вместе с объектом действия, являются необязательными и зависят от логики, используемой для обновления state.

8. Создание представления/ пользовательского интерфейса

Теперь, когда мы создали все необходимые объекты, такие как Store, Actions и Reducers, пришло время создать элементы пользовательского интерфейса. Создайте папку component внутри src и создайте в ней файл Cart.js. Добавьте следующую строку внутри Cart.js

import React from "react";

const Cart = () => {
  return (
    <div className="cart">
      <h2>Number of items in Cart:</h2>
      <button className="green">Add Item to Cart</button>
      <button className="red">Remove Item from Cart</button>
    </div>
  );
};

export default Cart;
Войти в полноэкранный режим Выйти из полноэкранного режима

Добавьте этот компонент Cart в App.js.

import "./App.css";
import { Provider } from "react-redux";
import store from "./store";
import Cart from "./component/Cart";

function App() {
  return (
    <Provider store={store}>
      <Cart />
    </Provider>
  );
}

export default App;
Войти в полноэкранный режим Выйти из полноэкранного режима

Чтобы сделать его немного презентабельным, я добавил немного базовой стилизации в App.css следующим образом.

button {
  margin: 10px;
  font-size: 16px;
  letter-spacing: 2px;
  font-weight: 400;
  color: #fff;
  padding: 23px 50px;
  text-align: center;
  display: inline-block;
  text-decoration: none;
  border: 0px;
  cursor: pointer;
}
.green {
  background-color: rgb(6, 172, 0);
}
.red {
  background-color: rgb(221, 52, 66);
}
.red:disabled {
  background-color: rgb(193, 191, 191);
  cursor: not-allowed;
}
.cart {
  text-align: center;
}
Вход в полноэкранный режим Выход из полноэкранного режима

Вот как выглядит пользовательский интерфейс на данный момент

9. Чтение/доступ к магазину с помощью хука useSelector

useSelector – это хук, предоставляемый библиотекой react-redux, который помогает нам читать store и, следовательно, его содержимое (содержимое). Импортируйте хук из react-redux и используйте следующий синтаксис для чтения магазина с помощью хука useSelector.

import { useSelector } from "react-redux";
// rest of the code
const state = useSelector((state) => state);

// rest of the code
Войти в полноэкранный режим Выйти из полноэкранного режима

Таким образом, после добавления хука useSelector, файл Cart.js будет выглядеть примерно так

import React from "react";
import { useSelector } from "react-redux";

const Cart = () => {
  const state = useSelector((state) => state);
  console.log("store", state);
  return (
    <div className="cart">
      <h2>Number of items in Cart:</h2>
      <button className="green">Add Item to Cart</button>
      <button className="red">Remove Item from Cart</button>
    </div>
  );
};

export default Cart;
Вход в полноэкранный режим Выход из полноэкранного режима

Консольный логгинг состояния даст нам начальное состояние, которое мы задали в файле reducer в шаге 5.

10. Диспетчеризация действия при нажатии на кнопку (наряду с обработкой некоторого поведения пользовательского интерфейса в зависимости от состояния) с помощью хука useDispatch.

Библиотека react-redux предоставляет нам еще один хук под названием useDispatch, который помогает нам диспетчеризировать действия или создателей действий, которые в свою очередь возвращают действия. Синтаксис выглядит следующим образом

const dispatch = useDispatch();

dispatch(actionObject or calling the action creator);
Войти в полноэкранный режим Выйти из полноэкранного режима

Таким образом, добавление диспетчера в наш Cart.js приведет к тому, что файл будет выглядеть примерно так

import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { addItem, deleteItem } from "../actions/cartAction";

const Cart = () => {
  const state = useSelector((state) => state);
  const dispatch = useDispatch();
  return (
    <div className="cart">
      <h2>Number of items in Cart: {state.numOfItems}</h2>
      <button
        onClick={() => {
          dispatch(addItem());
        }}
      >
        Add Item to Cart
      </button>
      <button
        disabled={state.numOfItems > 0 ? false : true}
        onClick={() => {
          dispatch(deleteItem());
        }}
      >
        Remove Item to Cart
      </button>
    </div>
  );
};

export default Cart;
Войти в полноэкранный режим Выход из полноэкранного режима

Обратите внимание, что при нажатии на кнопку Добавить товар в корзину, мы диспетчеризируем создателя действия addItem(), который мы создали в шаге № 7. Аналогично при нажатии на кнопку Remove Item from Cart мы отправляем создателя действия deleteItem(). Переменная state хранит состояние приложения, которое по сути является объектом с ключом numOfItems. Таким образом, state.numOfItems дает нам текущее значение количества товаров в магазине. Мы отображаем это в представлении в строке <h2>Количество товаров в корзине: {state.numOfItems}</h2>.

Если копнуть немного глубже, то при нажатии на кнопку Add Item to Cart происходит отправка создателя действия addItem(), который в свою очередь возвращает объект action с типом type: ADD_ITEM. Как упоминалось в первой части этой серии блогов, когда действие отправляется, все редукторы становятся активными. В данном примере у нас только один редуктор, а именно cartReducer, поэтому он становится активным и слушает диспетчеризацию action. Как показано на шаге 5, редуктор принимает состояние и действие в качестве входных данных, включает тип action и возвращает новый экземпляр обновленного состояния. В этом примере, когда действие с типом type: ADD_ITEM, соответствует первому случаю переключения, оно сначала делает копию всего состояния, используя оператор распространения ...state, а затем производит необходимое обновление, которое в случае добавления элемента равно numOfItems: state.numOfItems + 1, то есть увеличивает numOfItems на 1.

Аналогично, используя ту же логику, при нажатии на кнопку Remove Item from Cart, будет выполнено действие с типом type: DELETE_ITEM, которое переходит и уменьшает numOfItems на 1.

Вот демонстрация работающего приложения.

Обратите внимание, как мы смогли управлять поведением кнопки Remove Item from Cart на основе значения numOfItems в магазине redux. Поскольку отрицательное количество товаров не имеет смысла, мы отключили кнопку удаления товара из корзины, если state.numOfItems <= 0. Таким образом мы можем ограничить пользователя от уменьшения количества товаров в корзине, если оно уже равно 0. Это был базовый пример, показывающий, как мы можем контролировать поведение различных элементов DOM на основе внутреннего состояния приложения.

Ссылка на Github

Ссылку на Github проекта можно найти здесь: Ссылка на Github

Резюме

В этой статье мы узнали, как быстро раскрутить приложение react на базе redux. Мы узнали, как

  • Создавать действия, создателей действий, редукторы и магазин
  • Предоставлять магазин приложению с помощью <Provider>.
  • Считывать/получать доступ к хранилищу из компонентов с помощью хука useSelector и отображать информацию о состоянии в пользовательском интерфейсе
  • Диспетчеризация действий на пользовательские события, такие как нажатие кнопки, используя useDispatch hook
  • Управлять поведением DOM-элемента с помощью логики, основанной на состоянии приложения.

Подведение итогов

Спасибо за чтение! Я очень надеюсь, что вам понравилось читать о том, как раскрутить приложение на базе redux react, и вы нашли этот блог полезным. Не забудьте нажать кнопку “Мне нравится” и поделиться с друзьями, я буду вам очень признателен. Оставайтесь с нами, чтобы увидеть еще больше удивительного контента! Мир! 🖖

Социальные ссылки

  • LinkedIn
  • Сайт
  • Сайт блога

Оцените статью
Procodings.ru
Добавить комментарий