-
-
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
Flutter API #14
Comments
I think we can simply use a This is certainly the direction to take! |
I copied the update logic from |
Got it. We can also try to build a custom scheduler that will call the reaction only when there is a change. I think that will keep it clean and only rely on the public interface? I want to avoid using We haven't exposed the scheduler yet from a |
Hmm, I'm not sure how that would work with Flutter. The way the Reaction code works leaves the scheduling of We could hide the |
Oh, I meant the scheduler in the Reaction and not for Flutter. With a custom scheduler for a Reaction (which will have to be exposed in MobX), we can be efficient about calling At this point, this is pure hypothesis but I believe it will lead us to the right solution. |
👋 I'm the author of https://github.com/rrousselGit/flutter_hooks, a port to Flutter of React hooks. Considering mobx.js is creating mobx-react-lite using hooks, would that be worth considering to do the same with Flutter? |
Hello @rrousselGit ! Looks very interesting indeed. I'll have to dig a bit deeper to understand how it can simplify creating Flutter widgets for MobX. Any sample code I can look at to see a potential implementation of a flutter_hook for a mobx-observer widget? |
The example from the first post would become: class Greeter extends HookWidget {
@override
Widget build(BuildContext context) {
final name = useObservable('name');
return Text('Hello, ${name.value}');
}
} I don't fully understand |
From an API standpoint it's clearly a winner. I am curious what @katis thinks. Personally I have few questions:
|
Seems that
Right now I don't see how Dart also can't implement the But I can totally see myself using hooks in my own projects (with Mobx), so thanks for letting us know about |
Can you clarify a bit the following?
|
Hmm, actually, now that I think about it... class MyWidget extends HookWidget {
build(BuildContext c) {
useObserver(); // Kicks off mobx tracking "somehow"
return Container();
// after build returns, flutter_hooks internals call some lifecycle in the Observer hook
// that allows it to turn off mobx tracking.
}
} |
At least as a transitive dependency, yes.
If transitive dependencies are fine, then yes I don't see any issue with it. We could have: class MyStateless extends StatelessWidget {
@override
Widget build(BuildContext context) => Observer(builder: (context) {
final name = useObservable('Jane');
return Text('Hello, ${name.value}');
});
} slightly less convenient, but the user doesn't directly depend on |
Indeed. Flutter doesn't provide a |
Yeah, if it would be possible to have the hook execute a lifecycle method immediately after |
The lifecycle would need to be called even if |
Sounds good to me. I will create a From my understanding, that should cover the needs. |
Mobx will need a way to start and stop tracking separately to implement the hook. Now it always assumes that you provide a callback that is executed and changes inside are tracked. |
If you need to execute the end tracking functionality after the class MyWidget extends HookWidget {
build(BuildContext c) {
try {
useObserver(); // Kicks off mobx tracking "somehow"
return Container();
} finally {
// Will execute just before return, which means all the code that needs to be tracked would have executed
// pseudo-code
useObserver.endTracking();
}
}
}
|
@pavanpodila I love the callable class syntax, this allows some pretty cool naming for hooks! But realistically speaking, I do not think it is desired to ask users to write the |
@rrousselGit I meant this would be the wrapped code inside the builder. The end users will not be using the |
Similarly to the example here? #14 (comment) Indeed that's possible. But then I would suggest to make your own kind of widget that has a custom such that we have: class Greeter extends ObserverWidget {
@override
Widget build(BuildContext context) {
//
}
} where abstract class ObserverWidget extends HookWidget {
const ObserverWidget({Key key}): super(key: key);
@override
createElement() => ObserverElement(this);
}
class ObserverElement extends HookElement {
ObserverElement(ObserverWidget widget) : super(widget);
@override
ObserverWidget get widget => super.widget as ObserverWidget;
@override
void performRebuild() {
// track
super.performRebuild();
// end track
}
} |
I'll merge |
Starting from next week, I'll have a lot more free time, so I should be able to work on the hook integration. Should we make another issue to list what we want to do? We haven't decided on any prototype for anything yet besides a potential I gave it another look recently to see how mobxjs did it, and they have the following: const object = useObservable(someValue);
return <div>{object.field}</div> Since Flutter does not have mirroring, that API seem difficult to do. We can also think of having a dependency on the WIP code-generator to mark classes as |
I feel we should work on a non-trivial app to refine the API and smooth out any rough corners. I have been thinking of a few apps that we can build together and potentially also ship on the App Store 🤔 🦄 . That app will be the capstone example of MobX, with real-world use-cases. Do you think that will help in arriving at the ideal API? |
Agreed. At the very least, we'll want to contribute an example out there. |
@rrousselGit I think implementing hooks for disposable resources would be useful. Like I've experimented with the
|
I've been thinking, would that make sense to ask Flutter to expose the current It implies that we could have a custom Flutter observer that, when an observable is read, associate the current Which means we don't need |
@rrousselGit I'm not sure what you mean? Could you show an example? |
I wanted to remove the need for But after some thoughts, while this is technically possible, it would require a new kind of widget (and not work with |
Yeah, I think |
I think we also need a |
Why a This is not type safe and less performant than a Anyway, I made such provider here: https://github.com/rrousselGit/provider It should be a good source of inspiration |
I was going by the API in mobxjs :-). Your suggestion is much better. I think we should expose a Provider with those ideas, just to make it easy for our end users |
Provider seems very useful! Would be great to have it integrated with mobx.dart 😃 |
I'm not sure if it makes sense to include this in mobx. |
That's fair. So is the correct usage for Provider+MobX is something like the following? final state = MyState();
class MyApp extends StatelessWidget {
Widget build(ctx) {
return Provider<MyState>(
value: myState,
child: MaterialApp(
// ...
),
);
}
}
// Another file
class MyPage extends StatelessWidget {
Widget build(ctx) {
final state = Provider.of<MyState>(ctx);
return Observer(
builder: (ctx) {
return Container(
width: 20,
height: 20,
color: state.color,
);
),
);
}
} EDIT: Just realized I don't need to assign it in the outer scope: class MyPage extends StatelessWidget {
Widget build(ctx) {
return Observer(
builder: (ctx) {
final state = Provider.of<MyState>(ctx);
return Container(
width: 20,
height: 20,
color: state.color,
);
),
);
}
} |
If your app has a single store, you could just write the InheritedWidget yourself, 1 less dependency: // inject_my_store.dart
class InjectMyStore extends InheritedWidget {
InjectMyStore(this._store, Widget child) : super(child: child);
final MyStore _store;
static MyStore of(BuildContext context) {
final store = context.inheritFromWidgetOfExactType(InjectMyStore) as InjectMyStore;
return store._store;
}
@override
bool updateShouldNotify(InheritedWidget oldWidget) {
if (oldWidget is InjectMyStore) {
return _store != oldWidget._store;
}
return true;
}
}
// my_store.dart
class MyStore extends _MyStore with _$MyStore {
static MyStore of(BuildContext context) => InjectMyStore.of(context);
}
abstract class _MyStore implements Store {
@observable
foo = '';
}
// main.dart
void main() {
final store = MyStore();
runApp(InjectMyStore(store, RootComponent()));
}
class RootComponent extends StatelessWidget {
build(BuildContext context) {
final store = MyStore.of(context);
return Container();
}
} |
We need to start documenting all this on our site. This is going to be the first set of questions asked by anyone wanting to use MobX. Also part of the 0.1 release #97. I am going to spend the next week just doing docs 🚀 |
I think this is not very elegant, if you have more store, you will have to do this:
It would be nice if we could have a single |
Personally I've switched to a single appState Store instance to consolidate everything. I figured it's not as dangerous since only the observed fields will trigger re-renders for Observers, right? |
@crizant: You can use the Multiprovider. |
Thanks! how come I forgot to read the doc. |
Related to google/flutter-provide#3 There's an on-going discussion about merging all the different InheritedWidget wrapper and making one official solution, with the potential destination being
I'll keep you updated |
Great @rrousselGit. Definitely don't want any more duplicates from our end! |
Closing this issue as its getting into discussion mode :-) |
Does mobx flutter know when to dispose of the store automatically? Or do I have to explicitly call store.dispose() on each of my store? |
The Store's lifetime is your responsibility, so you will have to call dispose when you see fit |
Last night I thought I'd try to use Mobx with Flutter and created a simple widget based on the design of mobx-react and Flutter's ValueListenableBuilder:
usage:
It does seem to work and could be a starting point for the
flutter_mobx
API. Probably the life cycle of widgets will bring all kinds of problems like inmobx-react
.The text was updated successfully, but these errors were encountered: