Closed Luckey-Elijah closed 3 weeks ago
Currently, context_plus
doesn't provide a way to add a listener inside the build
method that would just fire the callback without causing the BuildContext
to rebuild.
The biggest reason why there's no such API yet is because I want the context_plus
to not only be convenient, but also correct. Just adding a .listen(context, (value) => <callback>)
will lead to potentially incorrect behavior if it's used conditionally since it's impossible to know which callback belongs to which code branch:
if (something) {
observable.listen(context, (value) => print('listener1'));
} else {
observable.listen(context, (value) => print('listener2'));
}
I haven't come up with an alternative approach that maintains both correctness and conciseness yet.
Okay, thank you very much for clarifying!
Here's what I'm doing currently to achieve what you were looking for:
final _listener = Ref<VoidCallback>();
...
_listener.bind(
context,
() {
void listener() {
print('Hello, callback!');
}
listenable.addListener(listener);
return listener;
},
dispose: listenable.removeListener,
key: listenable,
);
Looks quite massive, but does the job.
I'm considering options to make this more convenient. It looks possible to condense this into something like
final _listener = ListenerRef<AnyObservable>(); // or Ref<Listener<AnyObservable>>()
...
_listener.bind(
context,
observable,
() {
print('Hello, callback!');
},
);
I'm still yet to decide which syntax to choose for this, maybe I'll start a poll somewhere soon. :D Stay tuned!
After playing around with various options for implementing side effects, I suddenly realized that it's already there in an easy-to-use form. All you need is a .watchOnly()
call that always returns null.
So, to run a side effect on each notification from the observable
without causing the widget to rebuild you can do the following:
observable.watchOnly(context, () {
print('Hello, callback!');
return null;
});
That's it! As simple as that. Moreover, thanks to the behavioral rules of .watch()
and .watchOnly()
calls, the callback is replaceable via hot reload and should properly unregister as soon as the .watchOnly()
call disappears from the build
method automatically.
I'll add that to the examples soon.
UPD.
Sorry for the misguidance, late-night thinking provoked a rushed conclusion.
Unfortunately, watchOnly()
approach to side effects is not universal. It worked for me because I had all the side effects under a condition, like this:
observable.watchOnly(context, () {
if (!observable.didPrintHello) {
print('Hello, callback!');
observable.didPrintHello = true;
}
return null;
});
If I were to change this to just
observable.watchOnly(context, () {
print('Hello, callback!');
return null;
});
the print would've happened for each widget build, which is not what most package users would want.
So, side effects require a separate API, and I keep thinking about the available options.
Wow! Surprisingly elegant. Thank you for spending the time investigating this
@Luckey-Elijah sorry for the misguidance, please see an update on the comment above.
context_plus 4.0 and context_watch 5.0 now provide .watchEffect()
for all supported observable types.
I was looking into this package an curious how to perform side effect such as navigation with
context_plus
. I couldn't find much information on this on pub.dev or the docs