Closed MohiuddinM closed 10 months ago
why not
final userModel = watchtIt<UserModel>()
why not
final userModel = watchtIt<UserModel>()
This would trigger every time the model changes, but I only want to trigger on selected property. It can also work if watchIt
can take a selector as an optional arg.
hmm, that would make the Api more difficult to use, I would then use probably
final userModel = di<UserModel>()
watchPropertyValue((x) => x.isLoggedIn, target: userModel);
that communicate clearly what you want to do.
hmm, that would make the Api more difficult to use, I would then use probably
final userModel = di<UserModel>() watchPropertyValue((x) => x.isLoggedIn, target: userModel);
that communicate clearly what you want to do.
Ok, I got it thanks.
On another note, I was going through your code I found out that it depends on a global variable: https://github.com/escamoteur/watch_it/blob/337cf041a0cda58bead8a1f98ee652f4fa4474c6/lib/src/elements.dart#L3
Don't you think that could create a problem when multiple widgets are built? And also don't you just communicate between the widget and the element by simply passing the BuildContext to watch functions?
this is actually the trick that flutter_hooks to uses, its never a problem because dart flutter is single threaded only one widget is built at the same time, see https://github.com/escamoteur/watch_it#lifting-the-magic-curtain
Good to know. I saw it yesterday and was curious so I made a little POC to also understand how the thing works:
mixin WatchElement on ComponentElement {
final _listeners = <Listenable, ListenerEntry>{};
void watch<R extends Listenable>(R model, {Selector<R>? selector}) {
void callback() {
if (mounted) {
if (selector == null) {
return markNeedsBuild();
}
final selection = selector(model);
final oldSelection = _listeners[model]!.selection;
assert(selection is! Map || selection is! Set || selection is! List);
assert(
oldSelection is! Map || oldSelection is! Set || oldSelection is! List,
);
if (selection != oldSelection) {
markNeedsBuild();
}
_listeners[model] = ListenerEntry(callback, selection);
}
}
final selection = selector?.call(model);
final entry = ListenerEntry(callback, selection);
_listeners[model] = entry;
model.addListener(entry.callback);
}
void unwatch<R extends Listenable>(R model) {
final entry = _listeners.remove(model);
if (entry != null) {
model.removeListener(entry.callback);
}
}
@override
void unmount() {
_listeners.keys.forEach(unwatch);
super.unmount();
}
}
mixin Watchable {
R watch<R extends Listenable>(
BuildContext context,
R model, {
Selector<R>? selector,
}) {
if (context is! WatchElement) {
throw ArgumentError('watch can only be called inside WatchingWidget');
}
context.watch(model, selector: selector);
return model;
}
}
the intersting point comes when you want to allow multiple watches inside the same build method
the intersting point comes when you want to allow multiple watches inside the same build method
Do you mean multiple watches for the same model or different models?
Can me multiple watches on different properties of the same object or on different objects but inside the same build method. That's why the order of the watches has to stay the same between build alls as the only way to do that is to store the in a list and increment a counter on each watch call that gets reset to zero at tge begin of each build. Am 25. Aug. 2023, 23:12 +0200 schrieb Muhammad Mohiuddin @.***>:
the intersting point comes when you want to allow multiple watches inside the same build method Do you mean multiple watches for the same model or different models? — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>
My POC will work for multiple watches on the same model, I guess even if you change the order or use watch functions conditionally. E.g. Subscribe to a property only if there is a certain change.
I have uploaded the full code: https://github.com/MohiuddinM/watch_it_poc/tree/master
Thanks, will have a closer look at it soon
Similar to:
bool loggedIn = watchValue((UserModel x) => x.isLoggedIn)
but instead of returning the value it returns the notifier when the selected value (isLoggedIn
) changes:UserModel userModel = watchNotifier((UserModel x) => x.isLoggedIn)
.This function would be a shorthand for a
watchValue
followed by aget
.