Расширение сущности в редуксе - PullRequest
0 голосов
/ 27 апреля 2018

Мое состояние выглядит так:

state = {
  entities: {
    users: {},
    articles: {},
  },
  pagination: {
    articlesByUser: {
      1: { // userId = 1
        isFetching: true,
        ids: [],
      },
      2: { // userId = 2
        isFetching: true,
        ids: [],
      },
    },
  },
}

это нормально для страниц со списками, но модели статей отличаются для маршрута index и get маршрута.

Ответ на index маршрут:

$ curl http://api//articles
[{
  "id": 0,
  "user_id": 0,
  "title": "...",
  "short_description": "...",
  ...
}
...
]

Ответ на get маршрут:

$ curl http://api//articles/0
{
  "id": 0,
  "user_id": 0,
  "title": "...",
  "body": "...",
  "meta": {...},
  "view_count": 100,
  ...
}

Сущности разные. GetModel запрос на продление IndexModel. Поэтому состояние pagination редуктора должно выглядеть так:

pagination: {
  articlesByUser: {
    1: { // userId = 1
      isFetching: true,
      ids: [],
    },
    2: { // userId = 2
      isFetching: true,
      ids: [],
    },
    ...
  },
  articleByArticleId: {
    1: { // articleId = 1
      isFetching: true,
    },
    ...
  }
},

Как лучше структурировать pagination редуктор в этом случае для состояния загрузки ручки (isFetching = true) для одного и многих изделий?

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

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

Вы можете просто использовать 2 объекта: users и articles для хранения всех данных пользователей и статей, включая isFetching статус и частичные данные из api/articles:

state = {
  users: {
    1: { // userId === 1
      name: 'John', // user properties
      articles: [1, 2, 5], // article ids associated with user
    }
  },
  articles: {
    1: { // articleId === 1
      title: '...',
      isFetching: true,
    }
  }
}

Затем, когда вы успешно получили статью из api/articles/:id, вы можете отправить действие SET_ARTICLE_DATA со статьей id и data и заменить частичные данные статьи в редукторе статей (при условии, что вы сохраняете статьи состояние в отдельном редукторе):

case SET_ARTICLE_DATA:
  return {
    ...state, // clone existing articles
    [action.id]: { // replace article with id === `action.id` with received data
      ...state[action.id], // not needed if `action.data` has everything u need
      ...action.data,
      isFetching: false, // can use object destructuring on `state[action.id]` to remove this key too
    } 
  }
0 голосов
/ 27 апреля 2018

Я не знаю, что означают ваши ссылки на модели; я предполагаю, что вы говорите о моделях на бэкэнде, но это на самом деле не влияет на нас, поэтому я буду их игнорировать.

Использование действий для извлечения и форматирования данных в Redux

Давайте начнем с этого утверждения:

Работает нормально для страниц со списками, но модели статей отличаются для индексного маршрута и получают маршрут

Это на самом деле не имеет значения! Это нормально, что данные различаются между маршрутами (даже если они не идеальны).

Я не знаю, где вы сейчас обрабатываете свои запросы API, но я рекомендую поместить их в действия Redux. Используя промежуточное ПО Redux Thunk , мы можем иметь функции в наших создателях действий. Частью работы действия является подготовка данных для редуктора. Это означает, что мы можем использовать функции в действиях для форматирования данных, чтобы они всегда были одинаковыми при попадании в редуктор. Это означает, что нам не нужно писать много похожих редукторов для обработки одного и того же типа сущности, сохраняя вещи СУХИМЫМИ и делая их намного проще в обслуживании.

В этом сценарии у меня будет три действия:

getAllArticles()

getArticlesById(id)

putArticles(articles)

Два действия get article будут отвечать за выполнение запроса, форматирование данных. Затем они берут эти данные и передают их putArticles, который фактически отправляет действие, которое ожидает редуктор.

Ваши методы будут выглядеть примерно так:

const getAllArticles = () => {
   return (dispatch, getState) => {
      fetch(yourRoute).then((json) => {
        const formattedData = json // format/normalize your data here
        dispatch(putArticles(formattedData))
      }
   }
}

const getArticleById = (id) => {
   return (dispatch, getState) => {
      fetch(yourRoute + id).then((json) => {
        const formattedData = json // format/normalize your data here
        dispatch(putArticles(formattedData))
      }
   }
}

const putArticles = (articles) => {
   return {
      type: 'PUT_ARTICLES',
      payload: {articles}
   }
}

Нормализующие данные

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

Я бы разбил ваш магазин по типу сущности.

state = {
   articles: {
      entities: { /* each article by ID */},
      result: [/* array of ID, primary used for looping */],
      pagination: { /* various pagination methods */ }
   },
  ...
}

Нормализация данных предотвращает создание формы с вложенными списками ресурсов (например, статьи> пользователи> комментарии). Вы в значительной степени сделали это, формализовав ее с помощью библиотеки, подобной Normalizr , которая позволит вам стандартизировать способ обработки данных.

Я бы переместил нумерацию страниц в отдельную сущность (пользователь, статья). Это позволяет аккуратно разделять вещи по их типу и предотвращает создание этого огромного списка несвязанных данных.

Углубление процесса нормализации в целом выходит за рамки вопроса SO, но взгляните на эти две ссылки:

Нормализация формы состояния Redux

Обновление нормализованных данных

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...