Начните отдельную 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 реализуется через eventChannel
s. Документы: 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);
}