Действия (Actions)

Во-первых, давайте определим некоторые действия.

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

Например, вот действие которое представляет добавление нового пункта в список дел:

{
  type: 'ADD_TODO',
  text: 'Build my first Redux app'
}

Действия - это обычный объект JavaScript. По соглашению, действия должны иметь строковое поле type, которое указывает на тип исполняемого действия. Типы должны, как правило, определяться как строковые константы. После того, как ваше приложение разрастется, вы можете захотеть переместить их в отдельный модуль.

import { ADD_TODO, REMOVE_TODO } from '../actionTypes';
Примечание к шаблону разработки

Вам не нужно определять константы типа действий в отдельном файле или даже определить их и вовсе. Для небольшого проекта, было бы проще просто использовать строковые литералы для типов действий. Однако, есть некоторые преимущества в явном объявлении констант в больших проектах. Прочтите Reducing Boilerplate для знакомства с большим количеством практических советов, позволяющих хранить вашу кодовую базу в чистоте.

Кроме type, структуру объекта действий вы можете строить на ваше усмотрение. Если вам интересно, изучите Flux Standard Action для рекомендаций о том, как могут строиться действия.

Мы добавим еще один тип действия, которое будет отмечать задачу, как выполненную. Мы обращаемся к конкретному todo по index, потому что мы храним их в виде массива. В реальном приложении, разумнее генерировать уникальный ID каждый раз, когда что-то новое создается.

{
  type: COMPLETE_TODO,
  index: 5
}

Это хорошая идея, передавать как можно меньше данных в каждом действии. Например, лучше отправить index, чем весь объект todo.

Наконец, мы добавим еще один тип действия для редактирования видимых в данный момент задач.

{
  type: SET_VISIBILITY_FILTER,
  filter: SHOW_COMPLETED
}

Генераторы действий (Action Creators)

Action creators - не что иное, как функции, которые создают действия. Довольно просто путать термины “action” and “action creator,” поэтому постарайтесь использовать правильный термин.

В традиционной реализации Flux, генераторы действий (action creators) при выполнении часто вызывают dispatch, примерно так:

function addTodoWithDispatch(text) {
  const action = {
    type: ADD_TODO,
    text
  };
  dispatch(action);
}

В противоположность этому, в Redux генераторы действий (action creators) являются чистыми функциями с нулевыми сайд-эффектами. Они просто возвращают action:

function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  };
}

Это делает их более подвижными (portable ориг.) и легкими для тестирования. На самом деле, чтобы запустить отправку действия - передайте результат action creator в функцию dispatch():

dispatch(addTodo(text));
dispatch(completeTodo(index));

Или создайте связанный генератор действия (bound action creator) который автоматически запускает отправку действия:

const boundAddTodo = (text) => dispatch(addTodo(text));
const boundCompleteTodo = (index) => dispatch(completeTodo(index));

Вы сразу же сможете его вызвать:

boundAddTodo(text);
boundCompleteTodo(index);

Доступ к функции dispatch() может быть получен непосредственно из хранилища (store) store.dispatch(), но, что более вероятно, вы будете получать доступ к ней при помощи чего-то типа connect() из react-redux. Вы можете использовать функцию bindActionCreators() для автоматического привязывания большого количества генераторов действий (action creators) к функции dispatch().

Исходный код

actions.js

/*
 * action types
 */

export const ADD_TODO = 'ADD_TODO';
export const COMPLETE_TODO = 'COMPLETE_TODO';
export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER';

/*
 * other constants
 */

export const VisibilityFilters = {
  SHOW_ALL: 'SHOW_ALL',
  SHOW_COMPLETED: 'SHOW_COMPLETED',
  SHOW_ACTIVE: 'SHOW_ACTIVE'
};

/*
 * action creators
 */

export function addTodo(text) {
  return { type: ADD_TODO, text };
}

export function completeTodo(index) {
  return { type: COMPLETE_TODO, index };
}

export function setVisibilityFilter(filter) {
  return { type: SET_VISIBILITY_FILTER, filter };
}

Дальнейшие шаги

Теперь давайте создадим несколько редьюсеров для того, чтобы описать как будет обновляться состояние (state) когда мы отправляем действия (actions)!

Для продвинутых пользователей

Если Вы уже знакомы с базовыми концептами и уже освоили этот обучающий материал, то не забудьте заценить асинхронные действия (async actions) в руководстве для опытных, чтобы научиться работать с AJAX ответами и создавать генераторы действий для асинхронного потока управления.