-
-
Notifications
You must be signed in to change notification settings - Fork 310
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tracking changes between start and end #19
Conversation
There's a branch on A typical implementation of void useObserver() {
Hook.use(const _ObserverHook());
}
class _ObserverHook extends Hook<void> {
const _ObserverHook();
@override
_ObserverHookState createState() => _ObserverHookState();
}
class _ObserverHookState extends HookState<void, _ObserverHook> {
@override
void initHook() {
// TODO: build Reaction
}
@override
void build(BuildContext context) {
// TODO: start tracking
}
@override
void didBuild() {
// TODO: stop tracking
}
} |
lib/src/core/tracking.dart
Outdated
/// This should only be used in situations where it is not possible to | ||
/// track changes inside a callback function. | ||
@experimental | ||
class Tracking { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about a more explicit name like DerivationTracker
? Going for a track-er rather than track-ing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use it in the current Reaction
, ComputedValue
implementations ? I think this would be an internally useful extraction of the tracking behavior
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll refactor context a bit, add most of the logic there, but I think this should be the public (and unsafe) API of doing tracking without callbacks. The callback API should be used for 99.9% use cases, even in Reaction & ComputedValue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree about using callbacks as they are more natural. Internally we can have a callback
interface to the start-end blocks of tracking. That way we are dog-fooding this Tracker
class and it becomes a core behavior (which it is really).
I would think of this as the antithesis of untracked()
. So a callback would be wrapped in tracked()
, which internally uses the Tracker with the start/end blocks.
Here is a sample implementation of tracked
(not tested).
dynamic tracked(void Function() fn, {ReactiveContext ctx}) {
final tracker = Tracker(context: ctx);
Tracker.start(); // ...
final result = fn();
Tracker.end(); // ...
return result;
}
test/tracking.dart
Outdated
import 'package:test/test.dart'; | ||
|
||
void main() { | ||
test('Tracking reacts to changes to reactive values between begin and end', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also have a test with a autorun() to ensure the reactions are kicked off when the observables change outside
I changed the The API is now: class DerivationTracker {
DerivationTracker(ReactiveContext context, Function() onInvalidate,
{String name});
void start();
void end();
void dispose();
} @rrousselGit I implemented the hook like this in my experiment, does it look OK to you? void useObserver({ReactiveContext context}) => Hook.use(context == null
? const _ObserverHook()
: _ObserverHook.withContext(context));
class _ObserverHook extends Hook<void> {
final ReactiveContext context;
const _ObserverHook() : context = null;
_ObserverHook.withContext(this.context) : super(keys: [context.hashCode]); // not sure about the keys
@override
_ObserverHookState createState() => _ObserverHookState();
}
class _ObserverHookState extends HookState<void, _ObserverHook> {
DerivationTracker _tracker;
@override
void initHook() {
super.initHook();
_initTracker();
}
@override
void didUpdateHook(_ObserverHook oldHook) {
super.didUpdateHook(oldHook);
_tracker?.dispose();
_initTracker();
}
void _initTracker() {
_tracker = DerivationTracker(hook.context ?? currentContext, _invalidate);
}
void _invalidate() => setState(noOp);
static void noOp() {}
@override
void build(BuildContext context) => _tracker.start();
@override
void didBuild() {
super.didBuild();
_tracker.end();
}
@override
void dispose() {
_tracker.dispose();
super.dispose();
}
} Usage would work like this: class CounterApp extends HookWidget {
@override
Widget build(BuildContext context) {
useObserver();
final counter = useMemoized(() => observable(0));
return GestureDetector(
onTap: () => counter.value++,
child: Center(
child: Text('Clicked ${counter.value} times',
textDirection: TextDirection.ltr, style: TextStyle(fontSize: 40)),
));
}
} |
@pavanpodila could we merge this now and think about the internal refactoring of ComputedValue etc. later? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall. Can we also use the DerivationTracker
in the ComputedValue
?
{String name}) | ||
: super(context, onInvalidate, name: name); | ||
: _reaction = Reaction(context, onInvalidate, name: name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not clear why we need a reaction
here for tracking? Could you please elaborate? Is it mostly to wrap the onInvalidate
in some derivation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically yes, I'm not sure how to do it better. DerivationTracker is pretty much Reaction, but with track
replaced with start
and end
, so it made sense to delegate to Reaction.
@katis There are some minor changes we can do, but that overall should do the trick, although I do not think there's a need for |
@rrousselGit Can I add you as a collaborator? I think you bring valuable expertise that we all can benefit from? |
Sure, please do so! 😄 |
You are now! Please confirm on the email link from github :-). Thanks! |
We could design a pretty elegant Flutter integration with
flutter_hooks
, but it requires a way to track changes between start and end with no ability to model them as a callback.I tried to design an API that supports the use case and hopefully prevents worst misuses,
but this should almost never be used.
Also added
dart:meta
and marked the Tracking class with an@experimental
annotation.See #14 for further discussion