I'm making a simple chat app to explore WebSockets and to practice applying TCA. It compiles and runs as intended, however, I'm not confident whether my code uses best practices regarding my custom WebSockets dependency.
In my ChatFeature, I declared the following actions (among others):
receiveDelta(String): appends theStringto a list in the feature's statesendButtonTapped: appends the contents of aTextFieldbinding to the same list, empty-strings the binding, and most importantly, has aruneffect:
return .run { send in
for await event in await self.chat.send(message) {
await send(.receiveDelta(event))
}
}
viewAboutToAppear: callsconnectof the WebSockets dependency to connect towss://ws.postman-echo.com/raw/which is a simple WebSockets server that just echoes whatever you send it.viewAboutToDisappear: callsdisconnectof the WebSockets dependency
Now, in my ChatClient, which implements the WebSockets dependency, I have:
struct ChatClient {
private static var task: URLSessionWebSocketTask? = nil
var connect: (_ url: URL) -> Void
var disconnect: () -> Void
var send: (_ message: Message) async -> AsyncStream<String>
}
The live implementation of ChatClient.connect assigns a new .webSocketTask to ChatClient.task and calls task!.resume() to start the connection.
The live implementation of ChatClient.disconnect calls task?.cancel(...) and nils out task.
Now here are my questions:
- Is it appropriate to persist the connection in
private static var taskofChatClient? - Is it appropriate to use
.onAppearand.onDisappearto send the.viewAboutToAppearand.viewAboutToDisappearactions to theviewStore? These actions connect/disconnect by working withChatClient.task.
Here's the full code. I realize this is more of a code review question but I want to be sure I am designing the dependency correctly before proceeding.