-
Notifications
You must be signed in to change notification settings - Fork 77
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
Ability to connect multiple models in connector (ScopedModel) #9
Comments
Thanks! Definitely an interesting idea. I'm a bit swamped right now and can't guarantee I'll be able to get this done in the next couple weeks, but I'll take a look at it and see how we can do it in a sane way. In order to support type safety, we'll need to carefully think about the API. For example, we could allow the user to provide a Therefore, we might need something like: new ScopedModel2<BookModel, CounterModel>(
models: [new BookModel(), new CounterModel()],
child: ...
); new ScopedModel3<BookModel, CounterModel>(
models: [new BookModel(), new CounterModel(), new SearchModel()],
child: ...
); As well as corresponding |
Definitely a fan of the type safe approach. Is it possible to have a class that accepts an infinite number of types in Dart? I was unsure about it. The other piece that I was unsure of is how those items would be destructured in the builder. After digging around Dart's documentation, I did find a pattern using mixins that seems equally robust w/o changing the api: class CounterModel extends Model {
var _counter = 0;
int get counter => _counter;
}
abstract class IncrementModel extends CounterModel {
void increment() {
// First, increment the counter
_counter++;
// Then notify all the listeners.
notifyListeners();
}
}
abstract class DecrementModel extends CounterModel {
void decrement() {
// First, decrement the counter
_counter--;
// Then notify all the listeners.
notifyListeners();
}
}
abstract class ResetModel extends CounterModel {
void reset() {
// First, reset the counter
_counter = 0;
// Then notify all the listeners.
notifyListeners();
}
}
class MainModel extends Model
with CounterModel, IncrementModel, DecrementModel, ResetModel {} This is a contrived example but it simulates how you can compose an infinite number of models together (similar to combineReducers in redux). |
Yah, that's an interesting approach. Just saw your blog post -- as an example without this context, this might a bit hard to follow (e.g. I first thought: Why doesn't he just put all of those methods together to form one logical model?). It might interesting to compose different types of State together, such as a |
Yes, I think that is a much better example that demonstrates the value. #laziness. I will probably update my post to include some context. |
Hi, |
@roeierez Yep, that's definitely true. I think this functionality might be useful in certain cases where you might want to combine different models together that are related for a specific part of the Widget tree without having to create 2-3 |
One of the problems I've been struggling with is passing multiple but different sets of data/models down the widget tree. In the simplest use case, I'd like to keep track of say AppConfig (a few app related items) and UserConfig (user data, permissions etc). I could make a larger AppState which includes both App, User and other classes, but for sake of keeping code isolated, would prefer separate models which I could pass down. |
Hey all, was just updating scoped model a bit and then it hit me: Listening to multiple models is actually pretty simple to do already. Honestly a bit embarrassed I didn't think of this earlier... In order to get one Widget to build with two models, you can just use the This still requires multiple class CombinedWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final username =
ScopedModel.of<UserModel>(context, rebuildOnChange: true).username;
final counter =
ScopedModel.of<CounterModel>(context, rebuildOnChange: true).counter;
return Text('$username tapped the button $counter times');
}
} |
Added an example here: Let me know if ya think this solves the issue! https://github.com/brianegan/scoped_model/blob/multiple-models/example/lib/main.dart |
@brianegan - thank you. Explains a lot of concepts nicely! Would work very well in my situation where we need about a couple of functional models - appglobals, userglobals and then some more on individual views. |
I changed the CounterHome widget in https://github.com/brianegan/scoped_model/blob/multiple-models/example/lib/main.dart as follows:
Why can we have effect of |
Hey hey :)
This is an interesting implementation detail! The InheritedWidgets are pretty cool -- they allow you to pass data down your Widget tree easily, and they also have a hidden superpower:
Therefore, every time the model changes, it will build a new The only advantage of the More info: |
@brianegan Thanks for your detailed explain. I suggest add
|
Thanks @jonahfang! Yah, was thinking the same thing, but wasn't sure if |
Are folks using this successfully? Does it solve the problem and feel like the issue can be closed? |
Hi Brian, I have adapted my code to work based on your multiple model sample. Works as advertised! Need to look at using the .of(context) in my fluro based route handlers to implement client side authorisation. Have no reason to think it would not work. |
Sounds good! I'll go ahead and close this out for now. Please let me know if you run into trouble, or spot any room for improvement in the API :) |
love scope_model approach, and yes , multiple model work perfect but with many models the init code it's a bit confused... |
Hi, |
As my understanding, I think when you use the |
in your multi model sample, you nested models . since your sample has only 2 models its ok, what if the app grows and at the end there be 10 models or more. should all those 10 models be nested inside each other ? |
I this way too. My app have five models, do I need to nest inside each other? There is a best way to do that? |
Hey hey -- Just a quick question: Do all of your models contain "Global" data that should be accessed anywhere? If so, then you'd need to currently nest your MaterialApp inside of all of them. If you only need to access some of these models on specific pages, you could nest a few "Global" models at the top level, and only instantiate new models when you navigate to the Routes that require them. Overall, I think it's smart to think about where you need data from a Scoped Model, and only provided that Data from that point down. However, if you really have 10 Models that need to be shared globally across your app, then we might need to think about reasonable alternatives to the current implementation. Unfortunately, the implementation details get tricky here -- if you try to avoid nesting, you often sacrifice some helpful functionality or make other things more complex. |
What the advantage of Scoped_Model when comparing with Redux and BLoC? |
All of these technologies can be used to separate View logic from Business Logic, they just differ in how they solve that problem. tl;dr: In my view, scoped_model is the simplest of the three. While BLoC & Redux are great, they are more complex than scoped_model. That often means you'll be writing a bit more code and need to understand a few more concepts to work with those patterns. The extra concepts in BLoC are Streams. Streams are really powerful, but take some time to learn. That extra power allows you to do some really neat things that you can't do with Models or Listenables, but the additional complexity might not always be worth it! I'd argue the same is true about Redux. It takes a bit longer to understand than scoped_model, but can give you some really nice benefits, such as being able Replay the actions a user took through your app. This is immediately useful for crash reporting and measuring user flows through your app. Hope that helps! |
@brianegan My boss give to me a project that is an app like Gmail. Suppose that you are building an Gmail app wich is the best approach: Redux, BLoC or ScopedModel? I just stopped the development after reaching this question, I do not want to build without a pattern and some time later have to refactor the whole project. Please give me some tips, it's always good to hear from experts. Thank you in advanced |
@pedromassango I recently build a navigation app, with complex data relation between widgets. I used scope model. I really love this pattern. Very simple and fast for refactoring. Before start my app, i try bloc pattern but, they need a redux to mantain the state, so the alternave to scope can be bloc pattern with redux. I m a angular developer and redux are a standard in complex app. They are very efficient and cover all your needs....but they are complex to mantain and, very hard for refactoring. Scope model are powerful like redux and simple to mantain. My advice is to take time to project your app life cycle, and be careful to use it in the right way, reloading only the widget you need to refresh. |
@gimox Me too. |
why it's giving error now and giving an error like "The class 'ConnectedModel' can't be used as a mixin because it extends a class other than Object" |
I was trying to solve multiple initialization problem and I've come up with this code class MultipleScopedModel extends StatelessWidget {
final List<Model> models;
final Widget child;
MultipleScopedModel({Key key, @required this.models, @required this.child})
: super(key: key);
@override
Widget build(BuildContext context) {
Widget mergedModels = child;
for (var model in models) {
mergedModels = ScopedModel(model: model, child: mergedModels);
}
return mergedModels;
}
} but for this initialization class Model1 extends Model {}
class Model2 extends Model {}
void main() {
runApp(MaterialApp(
home: MultipleScopedModel(models: [Model1(), Model2()], child: Home()),
));
}
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('hello'),
),
);
}
} the problem is that these initialized models are seen by dart as of generic type Model, not my custom classes e.g. Model1 or Model2. It is not possible to get it by ScopedModel because it can't find type Model1 or Model2 in the tree. The best solution would be something like final List<dynamic extends Model> models; but it is not allowed in Dart. Do you guys have any idea how to solve this issue? |
I am a big fan of unstated which takes advantages of React's new Context API and shares many similarities to this library.
It would be nice if you could combine multiple models in the subscriber
similar to how you can do it in unstated
The text was updated successfully, but these errors were encountered: