Возможно ли потерять данные при асинхронном обновлении состояния притока? - PullRequest
0 голосов
/ 09 апреля 2020

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

Я пишу приложение, которое подключается к внешней веб-розетке. Этот веб-сокет отправляет мне информацию о текущих чатах на другом сайте. Есть два примера сообщений websocket: chat_closed (информация о том, что чат с указанным идентификатором завершен) и incoming_event (информация о новом сообщении в теме с указанным идентификатором чата с указанным идентификатором).

В моем компоненте, где Я обрабатываю сообщения веб-сокета, которые я использую useDispatch, чтобы получить функцию отправки:

const dispatch = useDispatch()

Вот небольшой план моего обработчика сообщений веб-сокета:

websocketConnection.onmessage = evt => {
  const data = JSON.parse(evt.data)
  const { chat_id, thread_id, event, action } = data;
  switch (action) {
    case incomingEventWsAction:
      dispatch(pushEvent(chat_id, thread_id, event));
      break;
    case chatClosedWsAction:
      dispatch(closeChat(chat_id));
      break;
    default:
      break;
  }
}

pushEvent и closeChat return actions:

const pushEvent = (chatId, threadId, event) => ({
  type: PUSH_EVENT,
  chatId,
  threadId,
  event,
})

const closeChat = chatId => ({
  type: CLOSE_CHAT,
  chatId,
})

А вот редуктор, обрабатывающий эти действия (я использую функцию loda sh cloneDeep, чтобы избежать изменения состояния):

function rootReducer(state = initialState, action) {
  switch (action.type) {
    case PUSH_EVENT: {
      const chatsCopy = _.cloneDeep(state.chats)
      const targetChat = chatsCopy.find(c => c.id === action.chatId)
      targetChat.threads
        .find(thread => thread.id === action.threadId)
        .events.push(action.event)
      return {
        ...state,
        chats: chatsCopy,
      }
    }
    case CLOSE_CHAT: {
      const chatsCopy = _.cloneDeep(state.chats)
      const targetChat = chatsCopy.find(c => c.id === action.chatId)
      targetChat.closed = true;
      return {
        ...state,
        chats: chatsCopy
      }
    }
    default:
      return state
  }
}

А теперь вот пример ситуации:

  1. В состоянии избыточности у меня есть 2 текущих чата: A и B
  2. Новое сообщение веб-сокета поступает: новое событие в чате A
  3. Приложение установлено диспетчерское действие PUSH_EVENT, редуктор захватывает это действие и выполняет код внутри случая коммутатора PUSH_EVENT.
  4. Во время выполнения кода из 3. поступает новое сообщение websocket: чат B был закрыт
  5. Приложение отправляет действия на CLOSE_CHAT и ...?

А что происходит сейчас?

  1. Ожидание редуктора для последнего действия (добавление нового события в чат A и возвращение нового обновленного состояния) быть завершенным, а затем заботится о действии CLOSE_CHAT, используя новое обновленное состояние, которое было возвращено из последнего действия.
  2. Начинает ли редуктор немедленно выполнять код в случае CLOSE_CHAT, используя то же начальное состояние, что и предыдущее действие PUSH_EVENT? Если это так, это может привести к потере данных, потому что, например, если сначала действие CLOSE_CHAT завершится sh, а затем PUSH_CHAT завершится sh, то PUSH_CHAT вернет состояние, которое получено из исходного состояния, в котором не было информации о чате B будучи закрытым.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...