0

我正在学习 Redux-Saga,当他们登录并在注销时断开他们的连接时,我在理解将人们连接到聊天服务(Pusher 的 Chatkit)的正确流程时遇到了一些麻烦。

到目前为止,我有一个等待 LOGIN_REQUEST 操作的“auth”传奇,使用 axios 登录到 REST api,然后通过调用 USER_SET 操作将用户名和令牌存储在商店中。

我的问题是,当登录发生并存储凭据时,我应该放置一个名为 CHAT_CONNECT 的新操作,它会启动另一个传奇以连接到 Chatkit,还是应该让聊天传奇收听 LOGIN_SUCCESS 被触发和采取行动?这两种方法是否有任何实际差异。

作为一个额外的问题,使用 Redux Sagas 从 Chatkit 接收和处理新的 websocket 消息的最佳方式是什么?这是用于连接和接收来自聊天工具包的事件的样板代码。

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);
    })
4

1 回答 1

1

关于你的第一个问题:

我的问题是,当登录发生并存储凭据时,我应该放置一个名为 CHAT_CONNECT 的新操作,它会启动另一个传奇以连接到 Chatkit,还是应该让聊天传奇收听被触发的 LOGIN_SUCCESS 和采取行动?

根据所提供的信息,很难确定哪种方法是理想的,因为任何一种方法都将完成相同的功能。我看到的两种提议方法之间的最大区别是依赖的方向。您有两个不同的“模块”(功能、包、......无论您如何称呼处理单一职责的代码块),让我们调用它们log-inconnect-chat.

如果您CHAT_CONNECTlog-insaga 中分派一个动作,您的log-in模块将依赖于该connect-chat模块。据推测,该connect-chat动作将存在于connect-chat模块中。

或者,如果您的 connect-chatsaga 等待LOGIN_SUCCESS,那么您的connect-chat模块将依赖于您的log-in模块。据推测,LOGIN_SUCCESS将住在log-in模块中。

这两种方法都没有错。哪个最好取决于您的应用程序需求和功能。

如果您可能想在成功登录后的任何其他时间连接聊天,那么CHAT_CONNECT从您的log-insaga 中调度可能是有意义的。因为聊天不再依赖于登录。在某些情况下,任何一种方法都会比另一种更好,但这实际上取决于您的应用程序的其余部分是如何设置的。

关于您的奖金问题:

在 redux-saga 中挂钩外部事件的一种方法是通过eventChannels. 文档: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);
}
于 2018-08-12T19:21:33.467 回答