我正在学习Redux-Saga,在将人们登录并注销时断开他们与聊天服务(Pusher的聊天工具)的正确连接时遇到了一些麻烦。
到目前为止,我有一个“ auth”传奇,它等待LOGIN_REQUEST操作,使用axios登录到REST api,然后通过调用USER_SET操作将用户名和令牌存储在存储中。
我的问题是,当登录发生并存储了凭据时,我应该放置一个名为CHAT_CONNECT之类的新动作来启动另一个传奇来连接到Chatkit,还是应该让这个传奇来收听LOGIN_SUCCESS?被解雇并对此采取行动?这两种方法在实践上甚至没有任何区别。
作为一个奖励问题,使用Redux Sagas从Chatkit接收新websocket消息并对其采取行动的最佳方法是什么?这是用于连接和接收来自chatkit的事件的样板代码。
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);
})
答案 0 :(得分: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/#eventchannelsubscribe-buffer-matcher
有一些样板,但是我发现这种方法使测试更加容易,并且真正封装了外部功能。这是一个简单的示例,说明如何将事件通道连接到您提供的代码片段:
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);
}