确实是一个复杂的问题,我是Redux-Saga的新手,所以我将尽我所能解释。
我正在为连接聊天产品创建传奇。作为该连接过程的一部分,我必须提供处理程序来处理来自聊天产品的传入事件。有人告诉我Redux-Saga eventChannel是解决此问题的最佳方法,但是我在几个问题上感到困惑。
1)我必须从eventChannel返回一个取消订阅的函数,但是麻烦的是,当事件发射器被破坏时,我不想从聊天管理器中取消订阅。我处理从聊天管理器退订的方法是将连接存储在服务中(单例),并在注销时分派单独的操作,这将导致我的reducer断开连接。那么,当用户注销时,如果不调用Event Emitter的unsubscribe方法,我应该放入unsubscribe的内容是什么?
2)generate()函数似乎无法区分正在发出的事件。因此,如果我想从聊天服务中订阅几种不同类型的事件(用户收到消息,用户加入会议室等),我是否需要大量的eventChannels还是可以发出不同类型的事件?
3)大多数使用事件通道的示例都会先创建某种套接字或连接,然后将其传递给事件通道函数,然后再向其中添加事件。问题在于,Chatkit要求您订阅事件作为连接功能的一部分,因此连接功能必须位于事件通道创建功能内。有问题吗?
现在,我想知道为什么我需要使用事件通道。大概每次导入Chatkit的事件时,我都可以导入动作创建者并调度新动作。没有一个动作是异步的,因此大概可以想像,但是其中许多动作还是可以按顺序正确处理的?
抱歉,有很多问题,并且代码块很长,下面可能有很多错误,但这是我的第一个尝试。
function connect({username, chatManager, tokenProvider}) {
return eventChannel(emit => {
const userPresenceHandler = (event) => {
emit(event.payload)
}
const newMessageHandler = (event) => {
emit(event.payload)
}
const errorHandler = (errorEvent) => {
emit(new Error(errorEvent.reason))
}
chatManager.connect({
onUserCameOnline: userPresenceHandler,
onUserWentOffline: userPresenceHandler,
})
.then(user => {
user.rooms.map(room =>
user.subscribeToRoom({
roomId: room.id,
hooks: {
onNewMessage: newMessageHandler
},
})
)
})
.catch(error => console.log('Error on connection', error))
const unsubscribe = () => {
// I don't actually want to disconnect the chat manager here
}
return unsubscribe
})
}
function* connectFlow (username) {
try {
// Create Chat manager and store it in the chat service
const newChatManager = new Chatkit.ChatManager({
instanceLocator: chatConfig.instanceLocator,
userId: username,
tokenProvider: chatService.tokenProvider
})
chatService.chatManager = newChatManager
// Attempt the connection
const newCurrentUser = yield call(connect, {
username,
chatManager: chatService.chatManager,
tokenProvider: chatService.tokenProvider
})
// Store the currentUser in the chat service
chatService.currentUser = newCurrentUser
// Update the connecting state
yield put(doChatConnectSuccess())
} catch (error) {
// Dispatch the error action
yield put(doChatConnectError({
statusCode: error.statusCode,
errors: error.errors || [{message: 'Error connecting to Chatkit:' + error}]
}))
}
}
function* chatConnectSaga () {
while (true) {
// Wait for CHAT_CONNECT
const connectRequest = yield take(CHAT_CONNECT)
const { username } = connectRequest.payload
// Check username has been passed in to CHAT_CONNECT
if(username === undefined){
return
}
// Start a parallel task to do the actual connection
const connectTask = yield fork(connectFlow, username)
// Wait for the login to fail or the credentials to be unset
const action = yield take([CHAT_DISCONNECT, CHAT_CONNECT_ERROR])
// If CHAT_DISCONNECT was called then cancel any existing attempt to connect
if (action.type === CHAT_DISCONNECT) yield cancel(connectTask)
}
}