Сложные примеры редукционной петли?

Есть ли примеры использования redux-loop обрабатывать сложные рабочие процессы AJAX? Официальное репо очень минималистично. Из одного примера в дикой природе, который я смог найти ( https://hackernoon.com/why-i-wrote-a-redux-async-outerware-277d450dba74), кажется, что лупа очень похожа к редуксу

Вот несколько примеров сложных рабочих процессов AJAX:

  • Ajax Workflow1. Пользователь выбирает два разных фильтра в таблице результатов. Каждый фильтр инициирует запрос ajax, который затем разрешается не по порядку. Таблица результатов должна показывать правильный выбор фильтра. Ошибки не должны обновлять таблицу результатов.
  • Ajax Workflow 2
    • Пользователь начинает генерацию отчета (это длительный процесс).
    • Пользователь переключается на другой отчет. Следует либо отменить, либо проигнорировать ожидающее действие "ждать отчета".
  • Более сложный рабочий процесс (на основе старого примера redux-saga)
    • Пользователь нажимает кнопку входа в систему, которая запускает ajax-запрос для получения токена авторизации
    • Или
      • Пользователь сразу нажимает кнопку выхода из системы, которая должна отменить / игнорировать ожидающее действие авторизации
      • ИЛИ он должен хранить токен аутентификации при разрешении
    • Должен очистить токен авторизации после выхода из системы или в случае ошибки входа

1 ответ

Я дам выстрел на второй рабочий процесс (логин).

Прежде чем идти в код, стоит отметить redux-loop намного проще и предлагает меньше, чем redux-saga с точки зрения асинхронного управления потоком. Но в духе Elmосновное внимание уделяется потоку данных - что неудивительно, как правило, достигается типами данных. Поэтому полезно думать с точки зрения статически типизированного языка. В Haskell или же ElmВероятно, полезно смоделировать проблему по типу данных, который сам кодирует конечный автомат:

data LoginStatus data err =
    LoggedOut       | 
  , LoggedIn data   |
  , LoginError err  | 
  , Pending

куда data а также err Переменные типа представляют тип данных входа (токены) и ошибки входа. JavaScript, динамически типизируемый, не имеет смысла выражать ту же идею - но есть много динамических приемов, которые можно использовать для имитации теговых типов объединения, таких как LoginStatus, Без дальнейшего, вот код:

import {match} from "single-key";

export default function reducer(state, action) {
  return match(state, {
    LoggedOut : () => loggedOutReducer(state, action),
    LoggedIn  : () => loggedInReducer(state, action),
    Pending : () => pendingReducer(state, action),
    LoginError : () => loginErrorReducer(state, action)
  });
} 

Здесь я буду использовать простую и менее известную библиотечную единственную клавишу для достижения базовых типов объединения во время выполнения. "Одноключевой" объект, как следует из названия, - это объект, содержащий только ключ и значение, например { a: 1 } ("а" - это ключ, а 1 - это значение). Мы будем моделировать состояние с помощью одноключевых объектов - разные ключи представляют разные варианты LoginStatus, Несколько примеров состояний:

{
  LoggedOut : true
}


{
  LoggedIn : {
    token : 1235,
    user : { firstName: "John" }
  }
}

{
  Pending : true
}

После того, как это прояснено, вот субредукторы, используемые в главном редукторе:

// state :: { LoggedIn: {/* some data * } }
function loggedInReducer(state, action) {
  if (action.type === LOGOUT) {
    return {
      LoggedOut : true
    };
  }
  return state;
}
// state :: { Pending : true }
function pendingReducer(state, action) {
  if (action.type === LOGIN_SUCCESS) {
    return {
      LoggedIn : {
        token : action.payload.token,
        user  : action.payload.user
      }
    };
  }
  if (action.type === LOGIN_ERROR) {
    return {
      LoginError : action.payload;  
    };
  }
  if (action.type === LOGOUT) {
    return {
      LoggedOut : true  
    };
  }
  return state;
}
// state :: { LoggedOut : true }
function loggedOutReducer(state, action) {
  if (action.type === LOGIN) {
    return loop({ Pending: true }, Effects.promise(loginRequest));  
  }
  return state;
}
// state :: { LoginError : error }
function loginErrorReducer(state, action) {
  if (action.type === LOGIN) {
    return loop({ Pending: true }, Effects.promise(loginRequest));  
  }
  return { LoggedOut : true }; 
}

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

return loop({ Pending: true }, Effects.promise(loginRequest));

Это переходит из состояния LoggedOut/LoginError в Pending и укажите некоторые побочные эффекты - которые будут запланированы redux-loop, Вы даже можете объединить два варианта в один: { LoggedOut : error | null }, но я чувствую себя отдельно LoginError состояние выгодно в долгосрочной перспективе.

С некоторым представлением о типах данных эту проблему легче рассуждать, чем кажется на первый взгляд; Вы можете сделать то же самое с редуктором, примерно таким же, и использовать только redux-thunk,

Другие вопросы по тегам