Многие люди, с которыми я разговариваю, говорят:

Я понимаю и суть, и причину Redux ... Я просто теряюсь, пытаясь внедрить Redux в свое приложение React.

В этой статье мы разберем 3 шага, которые я использую для внедрения Redux в свои приложения React. В основном следование общественным стандартам плюс немного моего мнения, чтобы помочь организовать каталоги.

Отказ от ответственности:

  • Это предполагает базовые знания терминала и React
  • Все следующие цитаты взяты непосредственно из документации Redux. Обязательно перечитайте документы после прочтения этой статьи, и я уверен, что документы Redux будут иметь гораздо больше смысла
  • Окончательное репо проекта в конце
  • Я предлагаю один раз просмотреть статью, не следуя инструкциям, а затем перечитать и написать код

Давайте начнем с той же страницы, начнем с создания нового приложения React с помощью create-response-app, назовите его как хотите.

Теперь перезапишите src/App.js следующим кодом:

import React, { Component } from "react";
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      people: [{ id: 1, name: "Mesut Ozil" }],
      textInput: ""
    };
  }
  handleClick = () => {
    console.log(this.state.textInput);
  };
  handleChange = event => {
    this.setState({ textInput: event.target.value });
  };
  render() {
    return (
      <div className="App">
        <p>Add a New Player</p>
        <input type="text" onChange={this.handleChange} />
        <button onClick={this.handleClick}>Add</button>
        <ul>
          {this.state.people.map(p => {
            return <li key={p.id}>{p.name}</li>;
          })}
        </ul>
      </div>
    );
  }
}
export default App;

Это будет нашей отправной точкой. Список игроков, текстовый ввод для добавления новых игроков и кнопка для добавления нового игрока. npm start ваш проект, поиграйте и ознакомьтесь с нашей отправной точкой, если хотите.

Теперь, когда мы все на одной странице, пора представить Redux.

Вот наши глобальные цели для этой статьи:

  1. Уберите Месута Озила из нашего компонента приложения в наш магазин Redux (глобальное состояние)
  2. Когда мы нажимаем «Добавить», новые игроки будут добавлены в наш магазин Redux (глобальное состояние), а затем добавлены к нашему списку игроков при запуске приложения React.

Шаг 1 из 3

  • Установите зависимости Redux
  • начать нашу файловую структуру
  • создаем наше первое действие

Нам нужно установить два пакета. В вашем терминале введитеnpm install --save react-redux redux

Теперь в вашем /src/ каталоге создайте новую папку, redux в этой папке мы будем хранить все наши файлы Redux и действия в одном центральном месте.

отказ от ответственности: большая часть сообщества Redux не создает каталог redux. Они стремятся создать каталоги redux (т.е. действия, редукторы) прямо в каталог /src/. Но я чувствую, что это помогает мне хранить все данные, связанные с Redux, в одном месте для быстрой навигации.

Теперь давайте создадим наше первое действие.

Действие - это то, как изменяется ваше глобальное состояние. Вы можете думать о действии как о событии, которое запускается (от щелчка кнопки, когда компонент монтируется).

Действия - это полезные данные, которые отправляют данные из вашего приложения в ваш магазин.

Мы создадим действие, которое добавит нового игрока в наш список, и действие запускается, когда мы нажимаем кнопку Добавить.

Создайте здесь новый каталог /src/redux/actions. Давайте создадим новый файл и назовем его player.js. Откройте ваш player.js файл и создайте первое действие:

export const ADD_PLAYER = "ADD_PLAYER";
export const addPlayer = player => ({
 type: ADD_PLAYER,
 data: player
});

Первая строка позволит нам использовать этот тип действия в других файлах (что вы увидите на следующем шаге). Кроме того, отказ от строкового литерала упростит поиск ошибок. Например, если мы неправильно введем тип действия в любом файле, мы получим clearundefined error.

Под типом действия находится наше действие. Не выглядит слишком сложным, правда? Обычная функция JavaScript.

Берет игрока, которого мы хотим добавить, мы вводим свой тип действия, а затем отправляем его на следующий этап нашей сборочной линии. Объект, который мы возвращаем, будет иметь гораздо больше смысла на нашем следующем reducer шаге.

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

Зайдите в свой /src/app.js файл и добавьте import { addPlayer } from “./redux/actions/player.js”; под import React,...

Теперь замените то, что находится в функции handleClick, на

handleClick = () => {
  console.log(addPlayer(this.state.textInput));
};

Теперь npm start ваше приложение, введите что-нибудь в поле ввода текста и нажмите «Добавить». Теперь в консоли разработчика вы должны увидеть, как выглядит действие,

{type: “ADD_PLAYER”, data: “Alexis Sanchez”}
data:”Alexis Sanchez”
type:”ADD_PLAYER”

Вот как выглядит наше действие! Это то, что мы отправляем на шаг 2, чтобы определить, что делать.

Как видите, Action просто регистрирует и отправляет то, что произошло. Наш следующий шаг - определить, что делать.

На этом шаге мы настраиваем нашу среду, создаем наше первое действие и записываем его в консоль.

Вот наш код с шага 1:

Шаг 2 из 3

  • Создайте наши редукторы

Действия описывают факт, что что-то произошло, но не указывают, как состояние приложения изменяется в ответ. Это работа редукторов.

Давайте создадим наш редуктор.

Остановитесь и поразмышляйте над словом «редюсер», это поможет визуализировать этот шаг. То, что мы делаем, основано на типе действия (ADD_PLAYER), мы будем УМЕНЬШИТЬ правильный путь для изменения состояния.

В каталоге redux создайте новую папку и назовите ее reducers. Теперь в вашем каталоге reducer создайте 2 файла: 1) index.js, 2) player.js.

Структура каталогов пока должна выглядеть так:

-redux
--actions
---player.js
--reducers
---index.js
---player.js

Давайте сначала откроем reducers/index.js и введем следующее:

import { combineReducers } from "redux";
import player from "./player";
export default combineReducers({
 player
});

В нашем случае у нас есть только один редуктор, который будет обрабатывать наши действия, редуктор player.

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

Вместо одного большого файла-редуктора вы можете разбить их на отдельный файл.

По мере того, как ваше приложение становится более сложным, вы захотите разделить свою функцию сокращения на отдельные функции, каждая из которых управляет независимыми частями состояния.

Вспомогательная функция combineReducers превращает объект, значениями которого являются различные уменьшающие функции, в единую уменьшающую функцию, которую вы можете передать createStore.

Цель этого файла - объединить все наши редукторы. В нашем случае только один player.js редуктор. Единственный раз, когда вам нужно будет повторно посетить этот файл, - это добавить новый редуктор, который вы создали.

Теперь перейдите к нашему следующему файлу, reducers/player.js, чтобы начать писать наш первый редуктор.

import { ADD_PLAYER } from "../actions/player";
const initialState = {
 people: [{ id: 1, name: "Mesut Ozil" }]
};
function returnNameObj(name) {
 return {
  id: Date.now(),
  name
 };
}
const reducer = (state = initialState, action) => {
 switch (action.type) {
  case ADD_PLAYER:
   return {
    ...state,
    people: [...state.people, returnNameObj(action.data)]
   };
  default:
   return state;
 }
};
export default reducer;

Помните тип действия, который мы создали в нашем actions/player.js файле? Именно сюда мы импортируем его, опять же, чтобы помочь с ошибками, опечатками.

У нас есть вспомогательная функция returnNameObj , задача которой - создать наш новый объект игрока, который мы можем добавить к нашему массиву объектов people (см. Начальное состояние). Функция возвращает объект JavaScript с именем нового игрока, который мы добавляем, а также генерирует уникальный идентификатор с помощью Date.now (). В реальном мире я бы рекомендовал использовать что-то вроде UUID.

Затем мы собираемся создать наше начальное состояние, именно так мы устанавливаем наше начальное состояние в /src/App.js в состоянии нашего компонента, но теперь мы собираемся привести начальное состояние в redux.

Теперь о самой функции редуктора, мы берем два аргумента

  1. Наше начальное состояние (которое мы создали выше)
  2. Действие, поступающее из нашего actions/player.js файла

Когда мы выполняем действие, мы делегируем, какие изменения в состояние мы собираемся внести в зависимости от типа действия. Помните, что шаг 1 заключался в том, чтобы зафиксировать, какое событие было запущено, теперь мы определяем, что делать, основываясь на этом действии.

Например, если действие, поступившее в редуктор, имело тип действия ADD_PLAYER, то мы проходим простое выражение switch JavaScript, чтобы определить, какие изменения в состоянии мы должны внести.

Что вы должны никогда делать внутри редуктора:

Измените свои аргументы

Следовательно, когда мы попадаем в наш кейс ADD_PLAYER, мы сначала копируем существующее состояние, а затем переходим к созданию нового состояния. Никогда не изменяйте текущее состояние. Когда action.type соответствует регистру switch, происходят 3 вещи:

  1. Скопируйте наше существующее состояние
  2. Добавьте нашего нового игрока, который пришел с действием - помните data: player, когда мы создавали наши действия? Действие держитaction.type и action.data
  3. И, наконец, верните это нашему store, который хранит состояние нашего приложения (мы рассмотрим store на следующем шаге)

Вот код для двух новых файлов,

Шаг 3 из 3

  • Создайте наш магазин

В предыдущих разделах мы определили действия, которые представляют то, что произошло, и редукторы, которые обновляют состояние в соответствии с этими действиями.

Магазин - это объект, который их объединяет. У магазина есть следующие обязанности:

Сохраняет состояние приложения;

Разрешает доступ к состоянию через getState();

Позволяет обновлять состояние через dispatch(action);

… "Подробнее"

Мы почти там! Теперь нам нужно создать наш магазин. Клей для объединения действий, редукторов и состояний.

Хорошая вещь в файле магазина заключается в том, что вы создаете его один раз, и вам никогда не придется возвращаться к нему повторно.

В каталоге redux создайте новый файл с именем store.js со следующим:

import { createStore } from "redux";
import reducer from "./reducers";
const store = createStore(reducer);
export default store;

createStore Создает хранилище Redux, которое содержит полное дерево состояний вашего приложения.
В вашем приложении должно быть только одно хранилище.

Все просто, правда? Мы используем createStore function и передаем функцию reducer, которая отвечает за обновление нашего состояния в зависимости от того, какое действие оно было отправлено. Шаги, 1–2–3.

И последнее, прежде чем мы закончим с Redux, нам нужно обернуть наше приложение React нашим хранилищем Redux, которое представляет собой буквально две строки кода.

Откройте /src/index.js начните с импорта Provider вверху:

import { Provider } from "react-redux";

Тогда наш магазин Redux,

import store from “./redux/store”;

Теперь нам нужно обернуть наш <App /> поставщиком, чтобы мы могли получить доступ к нашему магазину из любого из наших компонентов, которые мы создаем, вы можете визуализировать этот шаг, поскольку мы отправляем данные всем нашим компонентам для доступа.

<Provider store={store}><App /></Provider>

Теперь вы видите закономерность?

  • Действие запускается, отправляется в Reducer
  • Редуктор определяет, как это повлияет на состояние.
  • обновляется единое дерево состояний store Redux

ARS - Действие, Редуктор, Магазин. Заблокируйте этот акрионим. Моя любимая футбольная команда - ARSenal, вот как я запоминаю этот поток.

Угадайте, что за люди? Готово!

Единственная оставшаяся часть - это подключение компонента React к нашему состоянию Redux.

Вернитесь в наш /src/App.js файл и давайте подключим наш компонент к нашему хранилищу Redux.

Начните с импорта connect из response-redux,

import { connect } from "react-redux";

Теперь прокрутите вниз и обновите свой экспорт, заключив его в connect, который выглядит так:

export default connect(mapStateToProps)(App);

И последний шаг, чтобы получить доступ к нашему состоянию Redux в компоненте, - это создать нашу mapStateToProps функцию, которая получает состояние Redux из-за нашей оболочки с connect, а затем позволяет нам получить доступ к состоянию из нашего компонента props.

Прямо над экспортом давайте создадим функцию

const mapStateToProps = state => {
  const ourReduxState = state;
  return { ourReduxState };
};

Мы можем назвать здесь свое состояние редукции как угодно и экспортировать для доступа нашего компонента. Я назвал его ourReduxState, чтобы помочь вам визуализировать, теперь мы можем получить доступ к этому состоянию из нашего компонента props.

Давайте удалим наше состояние, которое мы создали в нашем /src/App.js, и пройдемся по нашему состоянию Redux, чтобы вывести список наших игроков. Обновите this.state.people.map на this.props.ourReduxState.player.people.map, и все должно выглядеть так же. Различия? Вместо этого мы извлекаем данные прямо из состояния Redux.

Причина player.people в том, что мы настраиваем reducer, возвращаемся в player.js в вашем редукторе и проверяем наше начальное состояние.

И последний последний шаг (обещание) обновить вашу handleClick функцию в /src/App.js файле с помощью

handleClick = () => {
  this.props.dispatch(addPlayer(this.state.textInput));
};

Теперь введите текст в поле ввода и нажмите «Добавить», на экране должен появиться новый игрок - #mindblown. Этот игрок проходит через наш поток ARS. Что снова означает ARS?

Когда мы нажимаем «ДОБАВИТЬ», данные в нашем текстовом вводе отправляются как действие, которое передается нашему редуктору, который затем обновляет наше хранилище redux.

ДЕЙСТВИЕ

РЕДУКТОР

ХРАНИТЬ

Поскольку мы заключили наш компонент в оболочку withconnect, компонент знает, что нужно повторно отрендерить себя, чтобы отобразить только что добавленные данные в наше хранилище Redux.

Красивый.

Http://twitter.com/musa__b

Репо: https://github.com/mbarighzaai/redux-1-2-3