Обрабатывать нормализацию загруженных элементов в редукс-саге или редукторе?

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

Кто должен заниматься нормализацией?

Сама сага перед отправкой действия успеха с нормализованными данными?

Или маршрутизатор должен нормализовать дату перед построением нового состояния?

Редактировать Я решил нормализовать сагу и сохранить чистоту редуктора. Он просто заменяет действия новыми, которые activitiesUpdated ему дает.

Редуктор

export default function account(state = ACCOUNT, action) {
  switch (action.type) {
    case "account/LOGIN_SUCCESS":
      const { access_token, user } = action
      return { ...state, user, access_token, authenticated: true, error: "" }
    case "account/LOGOUT_SUCCESS":
      return ACCOUNT
    case "account/LOGIN_ERROR":
      return { ...state, error: action.error }
    case "account/ACTIVITIES_UPDATED":
      return { ...state, activities: action.activities }
    default:
      return state
  }
}

А это саги:

function sortActivities(activities) {
  return action.activities.sort((a,b) => b.timestamp.localeCompare(a.timestamp))
}

function addInvoices(activities) {
  let lastYearMonth, invoiceItem
  return activities.reduce((state, item, index) => {
    const currentYearMonth = item.timestamp.substr(0,7)
    if (currentYearMonth != lastYearMonth) {
      lastYearMonth = currentYearMonth
      invoiceItem = {
        id: currentYearMonth,
        type: "invoice",
        parking: 0,
        rebates: 0,
        sum: 0,
        timestamp: currentYearMonth
      }
      state.push(invoiceItem)
    }
    const amount = Math.abs(Number(item.gross_amount))
    if (item.type == "parking") {
      invoiceItem.parking += amount
      invoiceItem.sum -= amount
    } else if (item.type == "rebate" || item.type == "surplus") {
      invoiceItem.rebates += amount
      invoiceItem.sum += amount
    }
    state.push(item)
    return state
  }, [])
}

function *getActivities(access_token) {
  console.info("fetch activities")
  try {
    const activities = yield call(getActivitiesAsync, access_token)
    console.info("activities fetched")
    yield put(activitiesUpdated(addInvoices(activities.sortActivities(activities))))
  } catch (error) {
  }
}

function *updateActivities() {
  while (true) {
    const { access_token } = yield take(LOGIN_SUCCESS)
    console.info("Calling getActivities")
    yield call(getActivities, access_token)
    while (true) {
      const {type } = yield take([REFRESH_ACTIVITIES, LOGOUT])
      if (type == LOGOUT) {
        break
      }
      yield call(getActivities, access_token)
    }
  }
}

Когда вы думаете о двойных циклах while в саге updateActivities?

Также правильно ли

yield take([REFRESH_ACTIVITIES, LOGOUT])

это просто ярлык для

yield race[take(REFRESH_ACTIVITIES), take(LOGOUT)]


person philk    schedule 02.03.2016    source источник


Ответы (2)


В конечном счете, вы вольны делать все, что сработает для вас в этом случае — нет веских доводов в пользу одного над другим. В зависимости от того, как структурированы данные, вы можете обнаружить, что выполнение этого в саге будет иметь меньше кода, потому что вы разбираете результат только один раз против двух (один раз в каждом из двух редукторов, которые заботятся о данных. Но это может быть, а может и не быть.Мне также нравится идея сделать это в редьюсере, потому что редукторы обычно должны быть максимально простыми, и эта модель соответствует этому.

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

person Nathan Hagen    schedule 02.03.2016
comment
Я обновил свой вопрос кодом, который я использую в банкомате. - person philk; 03.03.2016

Также вы можете использовать createSelector для нормализации данных, чтобы саги оставались чистыми:

- Selectors can compute derived data, allowing Redux to store the minimal possible state.
- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.
- Selectors are composable. They can be used as input to other selectors.
person Alex    schedule 09.07.2021