I want my Selector to only rebuild when the email value changes, but when it does, I want to use the ChangeNotifier on its builder, as an example:
Selector<MyChangeNotifier, String>(
selector: (_, model) => model.email,
builder: (_, email, __) {
if (email == null) {
return Container();
} else if (isNotBlank(email)) {
return RaisedButton(
onPressed: () => // use model here,
child: Text('Verify ${email}'),
),
);
} else { // empty email
return RaisedButton(
onPressed: () => // use model here,
child: Text('Continue'),
);
}
},
)
I know I can use a Consumer or Provider.of, but Selector is more optimized.
It seems like a feature request, but for now only way to access to the model in this scenario is using Provider.of.
Selector only exposes the changed value, so you have to use Provider.of<MyChangeNotifier>.of(context, listen: false); in the builder block.
Selector<MyChangeNotifier, String>(
selector: (_, model) => model.email,
builder: (context, email, __) {
final model = Provider.of<MyChangeNotifier>(context, listen:false);
... /// now you can use your model anywhere in the builder block.
},
)
I know, that's what I said on my last sentence, I am asking for a feature request.
I don't like it.
It's a big breaking change and relatively dangerous.
This means that people can use _inside build_ values other than the value selected.
It'd be easy to end up in a situation where our widgets aren't updated but it'd be difficult to see.
The worlkflow I'd expect people to do is to call Provider.of directly inside the event handler:
selector: (context, value, _) {
return RaisedButton(
onPressed: () {
final model = Provider.of<Model>(context, listen: false);
},
child: Text('$value');
);
}
Calling it inside _onPressed_ and nowhere else has two benefits:
model isn't used to build the widget treelisten: false if we forgotI am currently calling Provider.of inside onPressed, but in my opinion if people are using Selector it's because they know they are filtering their updates already, so they shouldn't be surprised if the widgets don't update, as it was their choice.
I have a better proposal.
As a recent experiment, I successfully implemented the "selectors" pattern as a static method (similar to Provider.of).
As such, you could write:
Widget build(context) {
final name = context.select((Person p) => p.name);
final age = context.select((Person p) => p.age);
return Text('$name $age');
}
Which is a lot more readable than Selector, and therefore kinda takes over this issue
Thought?
I really like it! I believe it also has listen = false right?
Also, why select and not filter? Select is too technical and not as readable IMO.
I believe it also has listen = false right?
No. There's no need for it. There's no reason to use select without listening to the object.
why select and not filter
It matches Selector and is the proper term.
That term is widely used in React for instance.
There's no reason to use select without listening to the object.
Yeah, makes sense.
That term is widely used in React for instance.
I never used React before, so I guess it's OK then, I was more worried about people not fluent in English.
This proposal looks really great !
Maybe one problem is that it will not be easy to use it in deep widget tree :
in the following code, Selector is verbose but it's easy for newcomers to understand that only Selector subtree will rebuild when needed :
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
...
),
body: Selector<TodoListModel, Todo>(
selector: (_, model) => model.todoById(id),
builder: (context, todo, _) {
return Padding(...
With the new syntax, rebuilding more than needed will be an easy mistake for newcomers :
Widget build(BuildContext context) {
Todo todo = context.select((TodoListModel model) => model.todoById(id));
return Scaffold(
appBar: AppBar()
...
),
body: Padding(...
Maybe one problem is that it will not be easy to use it in deep widget tree :
I don't think that's really an issue.
People can use the "extract to new widget" refactoring tool, or use Builder. And Selector/Consumer won't be removed
I think the docs should point that out, but the library should provide (pun intended) this functionality, since advanced users shouldn't be restricted to what won't confuse beginners.
As long as the docs are clear on the possible side effects, I think it will be fine.
Closing as context.select has landed
Most helpful comment
I have a better proposal.
As a recent experiment, I successfully implemented the "selectors" pattern as a static method (similar to Provider.of).
As such, you could write:
Which is a lot more readable than
Selector, and therefore kinda takes over this issueThought?