如何在@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());
}
}
但是这会带来问题,因为有两种情况:
当用户登录时,例如在名为 LoginScreen
的组件中有一个名为 login
的方法。 login
的方法做了两件事:
- 向 API 发送 POST 请求并获取令牌作为响应。
- 执行
WebSocket handshake
,然后 StompCommand.CONNECT
、StompCommand.SUBSCRIBE
。
如果用户按下 login button
,它将调用该方法。
当用户打开应用时:
App
组件将发送 GET 请求来验证令牌。如果令牌没有过期,它将执行WebSocket handshake
,然后StompCommand.CONNECT
,和StompCommand.SUBSCRIBE
。
问题是:
- 每个场景都需要访问
onStompErrorCallback
,我无法在不复制代码 increase code smell
的情况下将它放在任何地方,因为它取决于 dispatch(doSomething())
.
我尝试过的:
我尝试将 new Client(stompConfig: StompConfig)
存储到 redux。
Redux 无法存储 onStopErrorCallback: () => void
或 new Client(stompConfig: StompConfig)
。它会抛出一个错误。
我尝试使用自定义挂钩,例如 useStompClient(X_Auth_Token: string)
。
每次组件或屏幕调用 useStompClient(X_Auth_Token: string)
,它都会创建新的 stompClient
而不是使用现有的 stompClient
。
我尝试使用 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;
解决办法?创建第二层身份验证:
- 应用
- 身份验证层
- WebSocket层
哒哒!登录并打开应用程序场景,它会按预期工作。
解决办法?创建第二层身份验证:
- 应用程序:这是
Redux
和 NavigationContainer
所在的地方。
- AuthenticationLayer:这是
Stack.Navigator
所在的位置,例如
return (
<Stack.Navigator>
authenticated ? <Stack.Screen component={LoginScreen} /> : <Stack.Screen component={HomeScreen} />
</Stack.Navigator>
)
- 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.
哒哒!登录并打开应用程序场景,它会按预期工作。
我的目标是不重复 onStompErrorCallback
回调。
ps:我正在研究另一个解决方案,我认为它会起作用。
TL:DR
目前的解决方案是直接在React Hook中写onStopErrorCallback
function LoginScreen() {
const dispatch = useDispatch();
const onStopErrorCallback = (receipt: IFrame) => {
dispatch(doSomething());
}
}
但是这会带来问题,因为有两种情况:
当用户登录时,例如在名为
LoginScreen
的组件中有一个名为login
的方法。login
的方法做了两件事:- 向 API 发送 POST 请求并获取令牌作为响应。
- 执行
WebSocket handshake
,然后StompCommand.CONNECT
、StompCommand.SUBSCRIBE
。
如果用户按下
login button
,它将调用该方法。当用户打开应用时:
App
组件将发送 GET 请求来验证令牌。如果令牌没有过期,它将执行WebSocket handshake
,然后StompCommand.CONNECT
,和StompCommand.SUBSCRIBE
。
问题是:
- 每个场景都需要访问
onStompErrorCallback
,我无法在不复制代码increase code smell
的情况下将它放在任何地方,因为它取决于dispatch(doSomething())
.
我尝试过的:
我尝试将
new Client(stompConfig: StompConfig)
存储到 redux。Redux 无法存储
onStopErrorCallback: () => void
或new Client(stompConfig: StompConfig)
。它会抛出一个错误。我尝试使用自定义挂钩,例如
useStompClient(X_Auth_Token: string)
。每次组件或屏幕调用
useStompClient(X_Auth_Token: string)
,它都会创建新的stompClient
而不是使用现有的stompClient
。我尝试使用 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;
解决办法?创建第二层身份验证:
- 应用
- 身份验证层
- WebSocket层
哒哒!登录并打开应用程序场景,它会按预期工作。
解决办法?创建第二层身份验证:
- 应用程序:这是
Redux
和NavigationContainer
所在的地方。 - AuthenticationLayer:这是
Stack.Navigator
所在的位置,例如
return (
<Stack.Navigator>
authenticated ? <Stack.Screen component={LoginScreen} /> : <Stack.Screen component={HomeScreen} />
</Stack.Navigator>
)
- 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.
哒哒!登录并打开应用程序场景,它会按预期工作。