Начните отдельную Redx-сагу при входе и выходе

Я изучаю Redux-Saga и испытываю некоторые затруднения, оборачиваясь вокруг правильного потока для подключения людей к службе чата (Chatkit by Pusher), когда они входят в систему и отключают их при выходе из системы.

До сих пор у меня есть сага "auth", которая ожидает действия LOGIN_REQUEST, входит в REST API, используя axios, затем сохраняет имя пользователя и токен в хранилище, вызывая действие USER_SET.

Мой вопрос заключается в том, что когда происходит вход в систему и сохраняются учетные данные, я должен СДЕЛАТЬ новое действие, называемое чем-то вроде CHAT_CONNECT, которое запускает другую сагу для подключения к Chatkit, или я должен получить сагу чата для прослушивания запуска LOGIN_SUCCESS и действовать на это? Есть ли хоть какая-то практическая разница в этих двух подходах.

В качестве дополнительного вопроса, как лучше всего получать и обрабатывать новые сообщения веб-сокетов от Chatkit, используя Redux Sagas? Вот стандартный код для подключения и получения событий из чата.

chatManager
  .connect()
    .then(currentUser => {
      currentUser.subscribeToRoom({
        roomId: currentUser.rooms[0].id,
        hooks: {
          onNewMessage: message => {
            console.log(`Received new message: ${message.text}`)
          }
        }
      });
    })
    .catch(error => {
      console.error("error:", error);
    })

1 ответ

Решение

По поводу вашего первого вопроса:

Мой вопрос заключается в том, что когда происходит вход в систему и сохраняются учетные данные, я должен СДЕЛАТЬ новое действие, называемое чем-то вроде CHAT_CONNECT, которое запускает другую сагу для подключения к Chatkit, или я должен получить сагу чата для прослушивания запуска LOGIN_SUCCESS и действовать на это?

С предоставленной информацией трудно решить, какой подход является идеальным, потому что любой из них будет выполнять те же функции. Самое большое различие, которое я вижу между двумя предлагаемыми подходами, - это направление зависимости. У вас есть два разных "модуля" (функции, пакеты, ... как бы вы ни называли свои куски кода, которые обрабатывают одну ответственность), давайте их назовем log-in а также connect-chat,

Если вы отправите действие CHAT_CONNECT изнутри log-in сага, твой log-in модуль будет зависеть от connect-chat модуль. Предположительно, connect-chat действие будет жить в connect-chat модуль.

В качестве альтернативы, если ваш connect-chat сага ждет LOGIN_SUCCESSтогда ваш connect-chat модуль будет зависеть от вашего log-in модуль. Предположительно, LOGIN_SUCCESS будет жить в log-in модуль.

Нет ничего плохого в любом подходе. Что лучше, зависит от ваших потребностей приложений и функциональности.

Если вы хотите подключиться к чату в любое другое время, то после успешного входа в систему, возможно, имеет смысл отправить CHAT_CONNECT из вашего log-in сага. Потому что чат больше не зависит от входа в систему. Существует несколько сценариев, в которых один из подходов будет работать лучше, чем другой, но на самом деле это зависит от того, как настроена остальная часть вашего приложения.

По поводу ваших бонусных вопросов:

Один из подходов к перехвату внешних событий в redux-saga реализуется через eventChannels. Документы: https://redux-saga.js.org/docs/api/

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

export const createOnMessageChannel = () =>
  eventChannel((emit) => {
    chatManager
      .connect()
        .then(currentUser => {
          currentUser.subscribeToRoom({
            roomId: currentUser.rooms[0].id,
            hooks: {
              onNewMessage: message => emit({ message }),
            }
          });
        })
        .catch(error => emit({ error }));

    return () => {
        // Code to unsubscribe, e.g. chatManager.disconnet() ? 
    };
  });

export function* onMessage({ message, error }) {
  if (error) {
    yield put(handleError(error));
    return;
  }

  yield put(handleMessage(message));
}

// this is what you pass to your root saga
export function* createOnMessageSaga() {

  // using call because this makes it easier to test
  const channel = yield call(createOnMessageChannel);
  if (!channel) return;

  yield takeEvery(channel, onMessage);
}
Другие вопросы по тегам