Конечно, он его не изобретал. Но если бы посмотрел сегодня сливы собесов, точно увидел бы в них свои идеи. Ведь есть же фундаментальные идеи за всей этой шелухой про синтаксис mapStateToProps!

Тьюринг думает надо логотипом Redux
Тьюринг думает надо логотипом Redux

Императивное программирование

Допустим, вам поручили сделать web проигрыватель. Бизнес ставит задачи, сроки горят. Что делаем? Правильно, берём родной <audio>.

<audio src="https://cdn.pixabay.com/audio/2025/03/18/audio_7d5c12b31a.mp3"></audio>

Нужно будет лишь подписаться на его события.

// Обработчики событий элемента <audio>

audio.addEventListener("play", () => {
  // ...
});

audio.addEventListener("pause", () => {
  // ...
});

audio.addEventListener("ended", () => {
  // ...
});

// Обновление прогресса
audio.addEventListener("timeupdate", () => {
  // ...
});

Самое интуитивное желание — определить четыре флага для каждого возможного состояния проигрывателя. 

// Множество флагов состояния
var isPlaying = false;
var isPaused = false;
var isStopped = false;
var isEnded = false;

И на каждое событие проверить все флаги и выключить логически ненужные. В конце - перерисовать интерфейс. 

audio.addEventListener("play", () => {
  isPlaying = true;
  isPaused = false;
  isStopped = false;
  isEnded = false;

  updateUI();
});

Всё работает! Что ещё можно желать?

Ссылка на рабочий пример: https://jsbin.com/huyijutoyi/edit?js,output

Автоматное программирование

Проблема с флагами в их необязательности. Может ли проигрыватель быть одновременно в isPlaying и isEnded? По логике — нет, но в коде ничто не мешает этому случиться. 

В командной разработке нужно решение, которое сделает такие ошибки невозможными. Решение, которое облегчит жизнь не только программистам, но и бизнесу. И оно было придумано задолго до JavaScript — это конечные автоматы. Заметный вклад в объединение этой темы с программированием внёс Алан Тьюринг. 

Вернёмся в воображаемую контору. Вот планы команды на ближайшее будущее:

  • Записывать действия пользователей

  • Поддерживать состояния: volumechange, waiting, emptied 

  • Прислушаться к советам мудрого сторожилы конторы и использовать «design patterns» для разбиения на файлы

И всего через три итерации уже ясно, что следующая задача — документирование количества флагов и мест, где они могут меняться. 

Нужно решение! Чтобы большая команда делала меньше ошибок. 

Да и чтобы бизнес понимал какие состояния бывают и что умеет приложение.

Немного поискав информацию, можно найти прекрасные доклады и целую книгу:

Решено! Будем использовать наследие Алана Тьюринга и его современников - использовать конечные автоматы. 

Конечные автоматы

Посмотрим на схему работы, может что-то можно переписать иначе?

Три флага состояний
Три флага состояний

Нужно не улучшить текущий код, а переписать его заново (да, тоже нужно будет протолкнуть на планировании)!

Буквально, поменять эти флаги на состояние. Написать простую схему переходов между ними и запрограммировать с функцией-редуктором. 

Граф состояний
Граф состояний

Благо, в воображаемом примере не всё так плохо. Можно легко переписать флаги на множество управляющих состояний. 

// Множество управляющих состояний
var STATES = {
  STOPPED: "⏹️ Остановлен",
  PLAYING: "? Играет",
  PAUSED: "⏸️ Пауза",
  ENDED: "✅ Завершено",
};

А бизнес-логику приложения перенести из каждого события в функцию переходов (она же редуктор). 

// Функция переходов
function handleAction(action) {
  switch (action) {
    case "PLAY":
      if (currentState === STATES.STOPPED || currentState === STATES.PAUSED) {
        audio.play();
        currentState = STATES.PLAYING;
      }
      break;

    case "PAUSE":
      // ...
      break;

    case "STOP":
      // ...
      break;
  }

  updateUI();
}

Обновление интерфейса теперь простая задача: есть состояние - покажи сообщение. 

И так мы переехали на автоматное программирование!

  1. У нас есть единое управляющее состояние

  2. Логика переходов единственно, полно и декларативно описана в функции переходов

  3. Этот switch-case уже можно вынести в отдельную библиотеку!

Ссылка на рабочий пример: https://jsbin.com/kelukazovu/edit?js,output.

Redux

Так и сделаем! А потом, а потом…

  • Сделаем независимую от бизнес-логики библиотеку,

  • чтобы и в реакте работало,

  • чтобы и обновление частей состояния не вызывало перерисовки!!

  • Чтобы были плагины в браузере для истории переходов!

Постойте... нам что, нужен Redux?!

Конечно, для нашего такого проигрывателя — это стрельба из базуки по воробьям. Но главное – это фундаментальный принцип, на котором он построен. 

Redux — это не просто магический и новомодный синтаксис с экосистемой. Это, в первую очередь, реализация архитектурного шаблона конечного автомата, дополненная удобными инструментами (middleware, dev-tools).

Ссылка на рабочий пример с Redux: https://jsbin.com/wazimaziga/edit?js,output

Вывод

Так я показал проблему управления состоянием и её решения, начав аж с самого Тьюринга!

Я жалею, что никто не рассказывал мне про redux именно так. Большинство блогеров сразу переходят к синтаксису, не отвечая на вопрос: “оно вообще зачем нужно?”.

Так же я ранее рассмотрел и тему замыканий, начав с проблемы фунарга. И ещё много говорил про концепции React

Если вы есть, будьте первыми!

Комментарии (12)


  1. Tzimie
    13.11.2025 08:55

    Надо было начать с Рюрика


    1. Alexandroppolus
      13.11.2025 08:55

      Редукс существовал задолго до Рюрика, просто ещё не был открыт


      1. gev
        13.11.2025 08:55

        Еще в Древнем Риме! И уже потом его не Тьюринг, а Чёрч перепридумал для лямбда-исчисления!


      1. Tzimie
        13.11.2025 08:55

        Месье Платонист? Жму руку


  1. Arhammon
    13.11.2025 08:55

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


  1. nihil-pro
    13.11.2025 08:55

    А бизнес-логику приложения перенести из каждого события в функцию переходов (она же редуктор). 

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

    const handler = {
      currentState: undefined;
      
      handleEvent(event) {
        this.currentState = event.type;
        
        switch (event.type) {
          case "play":
              // ...
            break;
            
          case "pause":
            // ...
            break;
      
          case "ended":
            // ...
            break;
            
          case "timeupdate":
            // ...
            break;  
          case default;
            // ...
        }
      }
    }
    
    
    // audio = HTMLAudioElement
    
    audio.addEventListener(handler);
    // later
    audio.removeEventListener(handler);

    Какой практический смысл в том, что вы преобразовали play, pause, ended и timeupdate в PLAYING, STOPPED, PAUSED и ENDED?

    • Сделаем независимую от бизнес-логики библиотеку,

    Что вам это дало?

    • чтобы и в реакте работало,

    А если Vue? Angular? Solid?

    • чтобы и обновление частей состояния не вызывало перерисовки!!

    Значит ли это, что при обновлении части состояния, например с PLAYING на PAUSED, пользователь это не увидет?

    • Чтобы были плагины в браузере для истории переходов!

    Чтобы что? Для чего? Да, мы знаем, что редакс подает как мегафишку то, что вообще говоря почти никогда не требуется, а если требуется, то очень легко реализуется и без него?


    1. AlekseiVolkov Автор
      13.11.2025 08:55

      Отличный вопрос!

      А можно не выдумывать сложности там где их нет

      100% можно. Это лишь пример, именно в нём конечно не нужен редакс. Но и ваш пример как раз про автоматное программирование - переход от событийной логики в конечному автомату.
      Редакс это просто реализация такого подхода в реакте. Чтобы не всё приложение перерисовывалось и прочие плюшки.

      Что вам это дало?

      А если Vue? Angular? Solid?

      Это пример будущих мыслей бизнеса и техлидов.

      Значит ли это, что при обновлении части состояния, например с PLAYING на PAUSED, пользователь это не увидет?

      В реакте можем использовать редакс* в корне и он не будет вызывать перерисовок всего приложения.

      * – redux + react-redux

      Чтобы что? Для чего? Да, мы знаем, что редакс подает как мегафишку то, что вообще говоря почти никогда не требуется, а если требуется, то очень легко реализуется и без него?

      Чисто для отладки. Чтобы не console.log писать (даже через debugger), а видеть как менялось состояние. А как без редакса смотреть и менять состояние вашего примера handleEvent?


  1. adminNiochen
    13.11.2025 08:55

    Не знаю кто писал эту статью, но живые программисты не говорят "редуктор"


    1. merrick_krg
      13.11.2025 08:55

      Статью явно писал сантехник


  1. Egor_Grin
    13.11.2025 08:55

    какое счастье, что на первой работе, я попал в команду с тимлидом - джавистом, выбравшим для фронта Ангуляр...


  1. dominus_augustus
    13.11.2025 08:55

    Оказаться на проекте с редаксом - это боль
    Выбрать редакс целеноправленно - это диагноз


  1. AgentGenerous
    13.11.2025 08:55

    "Редукторы" это вещь! ...от которых мы сейчас всеми силами избавляемся и переходим на ванильный TS, именно как написал @nihil-pro