title: How to use dispatch inside onStompErrorCallback of @stomp/stomp-js library?
body: <p>My goal is to not duplicate <code>onStompErrorCallback</code> callback.</p>
  <p>ps: I am working on another solution, I think it would work.</p>
  <h3>TL:DR</h3>
  <p>The current solution is to write <code>onStopErrorCallback</code> directly in React Hook.</p>
  <pre><code>function LoginScreen() {
    const dispatch = useDispatch();
  
    const onStopErrorCallback = (receipt: IFrame) =&gt; {
      dispatch(doSomething());   
    }
  }
  </code></pre>
  <p>However this poses problem, because there are 2 scenarios:</p>
  <ol>
  <li><p>When a user login, e.g in a component called <code>LoginScreen</code> there is a method called <code>login</code>. The <code>login</code>'s method do 2 things:</p>
  <ol>
  <li>Send POST request to an API and get a token as response.</li>
  <li>Do the <code>WebSocket handshake</code>, and then <code>StompCommand.CONNECT</code>, <code>StompCommand.SUBSCRIBE</code>.</li>
  </ol>
  <p>If the user press the <code>login button</code>, it will invoke the method.</p>
  </li>
  <li><p>When a user open the app:</p>
  <ol>
  <li>The <code>App</code> component will send a GET request to authenticate the token. If the token is not expired, it will do the <code>WebSocket handshake</code>, and then <code>StompCommand.CONNECT</code>, and <code>StompCommand.SUBSCRIBE</code>.</li>
  </ol>
  </li>
  </ol>
  <p>The problem is:</p>
  <ol>
  <li>Each scenario needs access to the <code>onStompErrorCallback</code>, and I can't put it anywhere without duplicating the code <code>increase code smell</code> since it depends <code>dispatch(doSomething())</code>.</li>
  </ol>
  <p>What I've tried:</p>
  <ol>
  <li><p>I tried to store <code>new Client(stompConfig: StompConfig)</code> to redux.</p>
  <p>Redux can't store <code>onStopErrorCallback: () =&gt; void</code>, or the <code>new Client(stompConfig: StompConfig)</code>. It will throw an error.</p>
  </li>
  <li><p>I tried to use custom hook, e.g <code>useStompClient(X_Auth_Token: string)</code>.</p>
  <p>Each time a component or screen call <code>useStompClient(X_Auth_Token: string)</code>, it creates new <code>stompClient</code> instead of using the existing <code>stompClient</code>.</p>
  </li>
  <li><p>I tried to use a thunk to the <code>onStompErrorCallback</code></p>
  <p>The <code>stompClient</code> can't connect / subscribe / send message.</p>
  <pre><code>const onStompErrorCallback = (receipt: IFrame): AppThunk =&gt; dispatch =&gt; {
    dispatch(doSomething());
  }
  </code></pre>
  </li>
  </ol>
  <h3>Edit</h3>
  <p>This is the best I can do with custom hook. This is not a solution, the <code>useStompClient</code> see stompClient as null although it's not, and then it's re-render (this time it see stompClient as not null).</p>
  <pre><code>let stompClient: Client | null = null;
  
  function useStompClient(X_Auth_Token: string) {
    const dispatch = useDispatch();
  
    if (stompClient === null &amp;&amp; X_Auth_Token !== '') {
      const onConnectCallback = () =&gt; {
        console.log('STOMP: connecting');
        stompClient?.subscribe('/user/queue/messages', (message) =&gt; {
          const payload = JSON.parse(message.body);
          console.log(payload);
        });
      };
  
      const onStompErrorCallback = (receipt: IFrame) =&gt; {
        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;
  </code></pre>
  <p>The solution? Create a 2nd Layer authentication:</p>
  <ol>
  <li>App</li>
  <li>AuthenticationLayer</li>
  <li>WebSocketLayer</li>
  </ol>
  <p>Ta Da! Either login and open the app scenario, it would work as expected.</p>