Interview frequency: …
Short answer
Use clear states such as connecting, connected, disconnected, and error instead of scattered flags.
Explanation
Connection states branch among connecting, connected, reconnecting, disconnected, and failed, and affect the UI (a "no connection" banner), the logic (do we queue messages or reject them?), and retries. Multiple separate flags (isConnecting, isConnected, hasError) allow contradictory combinations, such as a connection being connected and failed at once. The solution is a sealed class or an enum that represents exactly one state at any moment, which the service exposes as a Stream or ValueListenable that the UI consumes, making it easy to test the transitions (connecting → connected → reconnecting) without a real network.
Code example
sealed class ConnectionState {
const ConnectionState();
}
class Connecting extends ConnectionState { const Connecting(); }
class Connected extends ConnectionState { const Connected(); }
class Reconnecting extends ConnectionState {
const Reconnecting(this.attempt);
final int attempt;
}
class Disconnected extends ConnectionState {
const Disconnected(this.reason);
final String reason;
}
class SocketService {
final state = ValueNotifier<ConnectionState>(const Disconnected('not started'));
// transitions are set in one place: state.value = const Connecting(); ... = const Connected();
}
// UI
ValueListenableBuilder<ConnectionState>(
valueListenable: service.state,
builder: (_, state, __) => switch (state) {
Connected() => const SizedBox.shrink(),
Connecting() || Reconnecting() => const LinearProgressIndicator(),
Disconnected(:final reason) => Text('Offline: $reason'),
},
);Common mistakes
- Treating the connection as "connected" as soon as connect is called, before the handshake actually completes.
- Leaving the old state after the connection closes, so the UI shows "connected" while it is cut off.
- Using several scattered boolean flags that allow impossible combinations instead of a single state.