En utilisant des rappels et des GlobalKey
, c'est bien pour des cas d'utilisation simples, mais pour des configurations plus complexes, ils devraient probablement être considérés comme des anti-patterns étant donné qu'ils se connectent à des types de widgets et dépendent de la logique d'implémentation de bas niveau.
Si vous vous retrouvez à ajouter de plus en plus de rappels/globalkeys, et que cela commence à devenir désordonné, alors il est peut-être temps de passer à quelque chose comme StreamController
+ StreamSubscription
. De cette manière, vous pouvez dissocier vos événements des types de widgets spécifiques et abstraire la logique de communication entre widgets.
Enregistrer un contrôleur d'événements
Dans votre widget de niveau supérieur (niveau de l'application ou niveau de la page en fonction de vos besoins), créez une instance de StreamController
et assurez-vous de la libérer dans la méthode dispose()
:
class _TopLevelPageState extends State {
StreamController eventController = StreamController.broadcast();
// ...
@override
void dispose() {
eventController.close();
super.dispose();
}
}
Passez l'instance de eventController
en argument de constructeur vers n'importe quel widget enfant qui doit écouter des événements et/ou déclencher des événements.
MyCustomEventType
peut être soit une énumération (si vous n'avez pas besoin de passer des données supplémentaires), soit un objet régulier avec les champs dont vous avez besoin au cas où vous auriez besoin de définir des données supplémentaires sur l'événement.
Déclencher un événement
Maintenant, dans n'importe lequel des widgets (y compris le parent, où vous avez déclaré le StreamController
), vous pouvez déclencher des événements avec :
eventController.sink.add(MyCustomEventType.UserLoginIsComplete);
Écouter des événements
Pour configurer un écouteur dans votre widget enfant (ou parent), placez le code suivant dans initState()
:
class _ChildWidgetState extends State {
@override
void initState() {
super.initState();
// REMARQUE : 'widget' est la référence par défaut à l'instance de `ChildWidget`.
this.eventSubscription = widget.eventController.stream.asBroadcastStream().listen((event) {
if (event == MyCustomEventType.UserLoginIsComplete) {
print('handling LOGIN COMPLETE event ' + event.toString());
} else {
print('handling some other event ' + event.toString());
}
}
@override
void dispose() {
this.parentSubscription.cancel();
super.dispose();
}
}
Soyez conscient que si vous remplacez StreamController.done(), alors vos écouteurs ne seront pas déclenchés car done()
remplace tous les écouteurs que vous avez définis précédemment.
REMARQUE : Si vous avez une relation de communication un-à-un entre deux widgets, alors vous n'avez pas besoin de la variante d'événements en diffusion - dans ce cas, vous pouvez créer le contrôleur sans .broadcast()
, c'est-à-dire avec StreamController()
et pour écouter au lieu de .stream.asBroadcastStream().listen()
vous pouvez utiliser .stream.listen()
. Voir également https://api.dart.dev/stable/dart-async/Stream-class.html
Pour une réponse qui décrit cette approche et d'autres méthodes, voir Communications entre widgets
0 votes
Peut-être un doublon de Déclencher une fonction à partir d'un widget vers un objet State
0 votes
Si vous pouvez vous assurer qu'un widget est un descendant d'un autre, vous pouvez utiliser InheritedWidget.
0 votes
@JacobPhillips Utilisez simplement
context.ancestorStateOfType
dans cette situation.0 votes
@RémiRousselet J'ai juste besoin d'un peu plus d'aide ici, j'essaie d'envoyer des données d'un widget enfant à un widget parent et tous les exemples de stream et listenable font l'inverse et c'est exactement mon problème. Je veux appeler une fonction d'un widget enfant à un widget parent, désolé de ne pas l'avoir mentionné ci-dessus.
1 votes
Transmettez l'intégralité du
StreamController
à votre enfant au lieu de simplementStream
si votre enfant doit également soumettre des événements.