flutter_comms
flutter_comms
builds on top of comms, making it easier to implement comms pattern
in Flutter projects.
For use in dart only projects, use comms.
Installation
flutter pub add flutter_comms
Basic usage
You can mix in Listener
and Sender
mixins to widgets but for more convenience
helper widgets have been prepared.
MessageListener
A MessageListener
works exactly like Listener
but calls listen
and cancel
functions for you, enabling it to receive messages from any Sender
sharing the
same message type.
MessageListener<MessageA>(
onMessage: (message) {
// handle received messages
},
onIntialMessage: (message) {
// handle initial message
},
child: Widget(),
)
MultiMessageListener
Merges multiple MessageListener
widgets, improving the readability of
nested MessageListener
s.
MultiMessageListener(
listeners: [
MessageListener<MessageA>(
onMessage: (message) {},
),
MessageListener<MessageB>(
onMessage: (message) {},
),
],
child: Widget(),
)
useMessageListener
useMessageListener
hook calls onMessage
every time a message of type Message
is received. Works similarly to Listener
but handles starting message receiving
and cleaning up itself.
This hook will receive messages only when HookWidget
using it is built.
Widget build(BuildContext context) {
useMessageListener<MessageA>(
(message) {
// handle received messages
},
onInitialMessage: (message) {
// handle initial message
}
);
}
Sending messages from State Management to UI
A typical real life use case of comms pattern is showing a toast or some popup with error or info message. States of any state management could be used for that but they are preserved even after the toast naturally disappears, so you have to clean the state yourself. With comms it's much more convenient.
class AuthNotifier with ChangeNotifier, Sender<AuthError> {
AuthNotifier(AuthRepository authRepository)
: _authRepository = authRepository;
final AuthRepository _authRepository;
bool _authenticated;
bool get authenticated => _authenticated;
Future<void> logIn(String username, String password) async {
try {
final loggedIn = await _authRepository.login(username, password);
if (loggedIn) {
_authenticated = true;
notifyListeners();
} else {
// All messages are cached to be able to use `onInitialMessage`. This
// time we need to set `oneOff` to `true`, otherwise on each Widget
// rebuild this message would be received. This still allows your
// widget to receive the message even if it gets build after message
// is sent, provided that this widget will be the first to receive it.
send(AuthError(message: 'Incorrect credentials'), oneOff: true);
}
} catch (e, st) {
send(AuthError(message: 'An unexpected error occurred'), oneOff: true);
}
}
...
}
We can use AuthError
messages as single-time events which disappear instantly after
displaying a snack bar, so no manual clean up is required.
class LoginScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MessageListener<AuthError>(
onMessage: (authError) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text(authError.message)),
);
},
child: LoginForm(),
);
}
}