Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

My goal is to not duplicate onStompErrorCallback callback.

ps: I am working on another solution, I think it would work.

TL:DR

The current solution is to write onStopErrorCallback directly in React Hook.

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

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

However this poses problem, because there are 2 scenarios:

  1. When a user login, e.g in a component called LoginScreen there is a method called login. The login's method do 2 things:

    1. Send POST request to an API and get a token as response.
    2. Do the WebSocket handshake, and then StompCommand.CONNECT, StompCommand.SUBSCRIBE.

    If the user press the login button, it will invoke the method.

  2. When a user open the app:

    1. The App component will send a GET request to authenticate the token. If the token is not expired, it will do the WebSocket handshake, and then StompCommand.CONNECT, and StompCommand.SUBSCRIBE.

The problem is:

  1. Each scenario needs access to the onStompErrorCallback, and I can't put it anywhere without duplicating the code increase code smell since it depends dispatch(doSomething()).

What I've tried:

  1. I tried to store new Client(stompConfig: StompConfig) to redux.

    Redux can't store onStopErrorCallback: () => void, or the new Client(stompConfig: StompConfig). It will throw an error.

  2. I tried to use custom hook, e.g useStompClient(X_Auth_Token: string).

    Each time a component or screen call useStompClient(X_Auth_Token: string), it creates new stompClient instead of using the existing stompClient.

  3. I tried to use a thunk to the onStompErrorCallback

    The stompClient can't connect / subscribe / send message.

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

Edit

This is the best I can do with custom hook. This is not a solution, the useStompClient see stompClient as null although it's not, and then it's re-render (this time it see stompClient as not 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;

The solution? Create a 2nd Layer authentication:

  1. App
  2. AuthenticationLayer
  3. WebSocketLayer

Ta Da! Either login and open the app scenario, it would work as expected.

question from:https://stackoverflow.com/questions/66050308/how-to-use-dispatch-inside-onstomperrorcallback-of-stomp-stomp-js-library

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
264 views
Welcome To Ask or Share your Answers For Others

1 Answer

The solution? Create a 2nd Layer authentication:

  1. App: This is where the Redux and NavigationContainer lives.
  2. AuthenticationLayer: This is where the Stack.Navigator lives, e.g
return (
  <Stack.Navigator>
    authenticated ? <Stack.Screen component={LoginScreen} /> : <Stack.Screen component={HomeScreen} />
  </Stack.Navigator>
)
  1. WebSocketLayer
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.

Ta Da! Either login and open the app scenario, it would work as expected.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...