Подтвердить что ты не робот

Магазин действий для оптимистичных обновлений - хороший подход в Redux/Flux?

Я работаю с оптимистичными обновлениями в приложении React + Flux и видел две вещи:

  • Что произойдет, если пользователь попытается закрыть окно, когда есть некоторые незавершенные действия. Например, в Facebook сообщение появляется в стене, даже если оно не было действительно сохранено (это то, что оптимистичные обновления делают, более отзывчивое приложение для пользователя). Но, если пользователь отправляет сообщение в стену и немедленно закрывает приложение (при выходе из системы или закрытии окна), сообщение может выйти из строя, и он не будет предупрежден.
  • Мне не нравится идея того, что магазины управляют своими собственными сущностями (например, сообщениями) и ситуацией действия, вызванным для продолжения сообщения (загрузка, succesfull, failed?). Он смешивает вещи.

Итак, я работаю над этим и создаю ActionStore, чтобы управлять состоянием действий, инициируемых компонентами. Вот исходный код и здесь - живая демонстрация.

Он работает примерно так:

  • Корень иерархии компонентов (контейнер в редуксе) выберет nextId нового действия и передаст его своим дочерним элементам, например, реквизитам (это уродливо).
  • Детский компонент запускает действие: он сохраняет actionId для запроса в хранилище после и вызывает создателя действия.
  • Создатель действия создает новое действие и возвращает функцию промежуточному программному обеспечению.
  • Функция, возвращаемая из Action, создает новое Promise с вызовом API и отправляет действие типа XX_START.
  • ActionStore прослушивает действие XX_START и сохраняет его.
  • Детский компонент получает новое состояние и находит действие с сохраненным идентификатором и задает ему текущую ситуацию: загрузка, успешность или неудача.

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

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

Примечание. Я работаю с одним веб-приложением одной страницы приложения с API-интерфейсом Rest, я не думаю, что использовать его при создании на стороне сервера

Это жизнеспособный вариант создания ActionStore или я ломаю некоторые фонды Redux/Flux? Это может положить конец возможности использования React Hot Reloading и Time travel?

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

4b9b3361

Ответ 1

Для будущих читателей, которые могут быть немного озадачены: мы больше не называем эти функции "магазинами": мы называем их редукторами. Итак, вопрос о редукторных запоминающих действиях.

Лично мне не нравится подход, который вы предлагаете. Вы вводите логику в действия и используете для этого наследование. Напротив, Redux предписывает действия как простые объекты без логики. Они не должны "знать", как обновлять какое-то состояние, и они не должны его удерживать - вместо этого они должны описывать, что произошло.

Я думаю, что подход для реализации оптимистичных обновлений в Redux похож на то, как вы реализовали Undo в Redux, который, в свою очередь, вдохновлен Архитектура влагостойкости. Идея состоит в том, что вы должны написать функцию, которая принимает редуктор (и некоторые параметры) и возвращает редуктор:

function optimistic(reducer) {
  return function (state, action) {
    // do something?
    return reducer(state, action);
  }
}

Вы использовали бы его как обычный редуктор:

export default combineReducers({
  something: optimistic(something) // wrap "something" reducer
})

Сейчас он просто передает состояние и действие в reducer, которое он обертывает, но он также может "запоминать" действия:

function optimistic(reducer) {
  return function (state = { history: [] }, action) {
    // do something with history?
    return {
      history: [...state.history, action],
      present: reducer(state.history[state.history.length - 1], action)
    };
  }
}

Теперь он накапливает все действия в поле history.

Опять же, это само по себе не очень полезно, но вы, вероятно, можете увидеть, как вы можете реализовать такой более высокий порядок редуктора, который:

  • отслеживает ожидающие асинхронные действия по своим идентификаторам и начинает запись истории, когда видит действие с status: 'request';
  • когда он получает действие с помощью status: 'done', сбрасывает историю;
  • когда он получает действие с помощью status: 'fail', настраивает историю, чтобы не включать начальное действие с status: 'request' и , повторно запускает редуктор, чтобы пересчитать текущее состояние, как будто запрос никогда не был.

Конечно, я не представил реализацию, но это должно дать вам представление о том, как реализовать оптимистичные обновления в режиме Redux.

Обновление: согласно комментарию OP, redux-optimist, похоже, делает именно это.