如何在@stomp/stomp-js 库的 onStompErrorCallback 中使用调度?

How to use dispatch inside onStompErrorCallback of @stomp/stomp-js library?

我的目标是不重复 onStompErrorCallback 回调。

ps:我正在研究另一个解决方案,我认为它会起作用。

TL:DR

目前的解决方案是直接在React Hook中写onStopErrorCallback

function LoginScreen() {
  const dispatch = useDispatch();

  const onStopErrorCallback = (receipt: IFrame) => {
    dispatch(doSomething());   
  }
}

但是这会带来问题,因为有两种情况:

  1. 当用户登录时,例如在名为 LoginScreen 的组件中有一个名为 login 的方法。 login 的方法做了两件事:

    1. 向 API 发送 POST 请求并获取令牌作为响应。
    2. 执行 WebSocket handshake,然后 StompCommand.CONNECTStompCommand.SUBSCRIBE

    如果用户按下 login button,它将调用该方法。

  2. 当用户打开应用时:

    1. App 组件将发送 GET 请求来验证令牌。如果令牌没有过期,它将执行WebSocket handshake,然后StompCommand.CONNECT,和StompCommand.SUBSCRIBE

问题是:

  1. 每个场景都需要访问 onStompErrorCallback,我无法在不复制代码 increase code smell 的情况下将它放在任何地方,因为它取决于 dispatch(doSomething()).

我尝试过的:

  1. 我尝试将 new Client(stompConfig: StompConfig) 存储到 redux。

    Redux 无法存储 onStopErrorCallback: () => voidnew Client(stompConfig: StompConfig)。它会抛出一个错误。

  2. 我尝试使用自定义挂钩,例如 useStompClient(X_Auth_Token: string)

    每次组件或屏幕调用 useStompClient(X_Auth_Token: string),它都会创建新的 stompClient 而不是使用现有的 stompClient

  3. 我尝试使用 thunk 到 onStompErrorCallback

    stompClient无法连接/订阅/发送消息。

    const onStompErrorCallback = (receipt: IFrame): AppThunk => dispatch => {
      dispatch(doSomething());
    }
    

编辑

这是我使用自定义挂钩所能做的最好的事情。这不是解决方案,useStompClient 将 stompClient 视为 null,尽管它不是,然后重新渲染(这次它看到 stompClient 不为 null)。

let stompClient: Client | null = null;

function useStompClient(X_Auth_Token: string) {
  const dispatch = useDispatch();

  if (stompClient === null && X_Auth_Token !== '') {
    const onConnectCallback = () => {
      console.log('STOMP: connecting');
      stompClient?.subscribe('/user/queue/messages', (message) => {
        const payload = JSON.parse(message.body);
        console.log(payload);
      });
    };

    const onStompErrorCallback = (receipt: IFrame) => {
      if (receipt.headers.message.endsWith('Access is denied')) {
        stompClient?.deactivate();
        dispatch(eraseCredentials());
      }
    };

    const stompConfig: StompConfig = {
      brokerURL: `${environment.wsBaseURL}/chat`,
      forceBinaryWSFrames: true,
      appendMissingNULLonIncoming: true,
      connectHeaders: {
        'X-Auth-Token': X_Auth_Token,
      },
      onConnect: onConnectCallback,
      onStompError: onStompErrorCallback,
    };

    stompClient = new Client(stompConfig);
  }

  return stompClient;
}

export default useStompClient;

解决办法?创建第二层身份验证:

  1. 应用
  2. 身份验证层
  3. WebSocket层

哒哒!登录并打开应用程序场景,它会按预期工作。

解决办法?创建第二层身份验证:

  1. 应用程序:这是 ReduxNavigationContainer 所在的地方。
  2. AuthenticationLayer:这是 Stack.Navigator 所在的位置,例如
return (
  <Stack.Navigator>
    authenticated ? <Stack.Screen component={LoginScreen} /> : <Stack.Screen component={HomeScreen} />
  </Stack.Navigator>
)
  1. WebSocket层
The WebSocketLayer requirements:
1. The `authenticated` is set to true, meaning the app already have the token and ready to be used.
2. Create the `onStompErrorCallback`, etc.
3. Put the stompClient and create a custom setters somewhere outside the React function.
4. Use React.useEffect() to set the stompClient.

哒哒!登录并打开应用程序场景,它会按预期工作。