Which is better when using provider instance in a new widget? - flutter

Let's say I've written my code as below.
I've got a provider called SampleProvider, and I'm using it in my main widget.
class SampleProvider extends ChangeNotifier {}
class MainWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
SampleProvider provider = Provider.of<SampleProvider>(context);
}
}
And then, I want to make a new widget and use this provider in the new widget.
There will be two choices.
First, I just instantiate another provider in the new widget as below.
class NewWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
SampleProvider provider = Provider.of<SampleProvider>(context);
}
}
Or, I can send it from the main widget to the new widget as a constructor parameter.
Like this:
class NewWidget extends StatelessWidget {
final SampleProvider provider;
NewWidget(this.provider);
#override
Widget build(BuildContext context) {
}
}
I guess the first option is better because flutter draws a widget based on its build context, but I'm not sure.
I've googled it quite long, but there was no success.
Can anybody tell me whether I am right or wrong? Or Do they have no difference?

Prefer the first solution, it's easier to refactor.
Suppose you need move NewWidget in your widget tree, you also need to modify the "paramter pass" code if you choose second solution, which is not necessary with first solution.
One of Provider pacakage's purpose is avoid passing parameter deep in the widget tree by the way.

Depend on preference not like first or second one.
Have an exception when obtaining Providers inside initState. What can I do?
This exception happens because you're trying to listen to a provider from a life-cycle that will never ever be called again.
It means that you either should use another life-cycle (build), or explicitly specify that you do not care about updates.
As such, instead of:
initState() {
super.initState();
print(context.watch<Foo>().value);
}
you can do:
Value value;
Widget build(BuildContext context) {
final value = context.watch<Foo>.value;
if (value != this.value) {
this.value = value;
print(value);
}
}
which will print value whenever it changes (and only when it changes).
Alternatively, you can do:
initState() {
super.initState();
print(context.read<Foo>().value);
}
SRC: https://github.com/rrousselGit/provider#i-have-an-exception-when-obtaining-providers-inside-initstate-what-can-i-do

Yes, I believe the first option is the better way, of the top of my head I can't think of any situation in which you would prefer the second option to the first.

If you don't use new widget as children of any other widget , first choice is better .
otherwise , second is better .

Related

How should I implement the init method? In a stateful or stateless widget?

What is the rule of thumb to use an initial method for a widget. Shall I use the:
A. classical stateful widget approach?
Or is it better to stick with the B. stateless widget approach?
Both seem to work from my testing. In terms of code reduction, it seems the B. approach is better, shorter, cleaner, and more readable. How about the performance aspect? Anything else that I could be missing?
Initializing a controller should be a one-time operation; if you do it on a StatelessWidget's build method, it will be triggered every time this widget is rebuilt. If you do it on a StatefulWidget's initState, it will only be called once, when this object is inserted into the tree when the State is initialized.
I was looking for initializing some values based on values passed in constructor in Stateless Widget.
Because we all know for StatefulWidget we have initState() overridden callback to initialize certain values etc. But for Stateless Widget no option is given by default. If we do in build method, it will be called every time as the view update. So I am doing the below code. It works. Hope it will help someone.
import 'package:flutter/material.dart';
class Sample extends StatelessWidget {
final int number1;
final int number2;
factory Sample(int passNumber1, int passNumber2, Key key) {
int changeNumber2 = passNumber2 *
2; //any modification you need can be done, or else pass it as it is.
return Sample._(passNumber1, changeNumber2, key);
}
const Sample._(this.number1, this.number2, Key key) : super(key: key);
#override
Widget build(BuildContext context) {
return Text((number1 + number2).toString());
}
}
Everything either a function or something else in widget build will run whenever you do a hot reload or a page refreshes but with initState it will run once on start of the app or when you restart the app in your IDE for example in StatefulWidget widget you can use:
void initState() {
super.initState();
WidgetsBinding.instance!
.addPostFrameCallback((_) => your_function(context));
}
To use stateful functionalities such as initState(), dispose() you can use following code which will give you that freedom :)
class StatefulWrapper extends StatefulWidget {
final Function onInit;
final Function onDespose;
final Widget child;
const StatefulWrapper(
{super.key,
required this.onInit,
required this.onDespose,
required this.child});
#override
State<StatefulWrapper> createState() => _StatefulWrapperState();
}
class _StatefulWrapperState extends State<StatefulWrapper> {
#override
void initState() {
// ignore: unnecessary_null_comparison
if (widget.onInit != null) {
widget.onInit();
}
super.initState();
}
#override
Widget build(BuildContext context) {
return widget.child;
}
#override
void dispose() {
if (widget.onDespose != null) {
widget.onDespose();
}
super.dispose();
}
}
Using above code you can make Stateful Wrapper which contains stateful widget's method.
To use Stateful Wrapper in our widget tree you can just wrap your widget with Stateful Wrapper and provide the methods or action you want to perform on init and on dispose.
Code available on Github
NOTE: You can always add or remove method from Stateful Wrapper Class according to your need!!
Happy Fluttering!!

Refactoring question: Extract as widget/method/variable... What are pros and cons?

All three of them do basically the same thing. What are the best practices? In which case shall I use which extracting way? What is the standard?
I guess these could be some points that could matter:
readability
performance
number of lines
Example:
Extract the Container. Which way would you prefer and why?
class Example extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container();
}
}
1. Extract Container as Widget (+6 lines):
class Example extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ExtractedAsWidget();
}
}
class ExtractedAsWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container();
}
}
2. Extract Container as Method (+1 (in some cases 3) line):
class Example extends StatelessWidget {
#override
Widget build(BuildContext context) {
return buildContainer();
}
Container buildContainer() => Container();
}
3. Extract Container as Variable (+1 line):
class Example extends StatelessWidget {
#override
Widget build(BuildContext context) {
var container = Container();
return container;
}
}
Extracting as Widget is the best practice as the Flutter framework can optimize widgets rather than methods or variables. But for this particular case, I would extract Container as method. Extracting as Widget would be too overkill.
Extracting as Variable
Extracting as variable should only be done when your widget is fixed, being used only in a single file & doesn't need any parameters.
Extracting as Method
Extracting as method should be done when your widget is being used only in a single file (and it can also use some parameters for additional customization). It also increases code readability.
Extracting as Widget
Extracting as Widget is the most optimal way to create a widget that is being used multiple times in different files. Flutter recommends creating as much StatelessWidget as possible.
The most simple example that I can suggest is the use of buttons. Every app has a fixed primary color button that we use. So, instead of creating a variable or method, we should create a StatelessWidget of that button & use that in multiple screens of our app.

Flutter Widget building & structure

It seems there is a lots of way to build Widget in Flutter. It is a bit overwhelming to understand the right way of doing it. Can anyone explain me the difference between defining a variable inside/outside the build function as follow:
Inside class
class Login extends StatelessWidget {
TextFormField username() {
return TextFormField();
}
#override
Widget build(BuildContext context) {
return Scaffold();
}
}
Inside build function
class Login extends StatelessWidget {
#override
Widget build(BuildContext context) {
TextFormField username() {
return TextFormField();
}
return Scaffold();
}
And also is there is any difference between defining the variable as follow:
class Login extends StatelessWidget {
final username = TextFormField();
TextFormField username() {
return TextFormField();
}
#override
Widget build(BuildContext context) {
return Scaffold();
}
}
Thanks a lot for your help.
Jonathan.
There are several ways to do anything within the programming world. With Flutter / Dart it would be no different.
However, there are more "orthodox" ways of doing things, which will certainly save you from structural problems.
1- Declaration of an instance.
When you have a class that is not a widget, you usually use common instances of classes.
String name = "Jonny";
TextEditingController controller = TextEditingController();
When you declare widgets, there are 3 ways to do this, but only 1 is recommended.
The first is to store the widget in a variable (just like we did above).
final text = Text ('Pablo');
Build widget (BuildContext context) {
return Scaffold (body: text);
The second, and least recommended of all, is to create a method that gives you an instance of that widget
Widget text () {
return Text ('Pablo');
}
Build widget (BuildContext context) {
return Scaffold (body: text ());
This second approach is less recommended, because you will manufacture a new instance every time the method is called. If this widget has a heavy rendering, you are throwing resources in the trash.
The third (and highly recommended, I would tell you to stick to it and forget about it any other way) is nesting widgets in the tree:
Build widget (BuildContext context) {
return Scaffold (body: Text ('Pablo'));
This ensures that the same instance of Text () remains on the tree, and consequently if it were a much larger widget, this would be the most resource-efficient approach.
What if my tree becomes giant? how to avoid the ripple effect?
Simple, create new StatelessWidgets to break the tree's cascading effect.
Build widget (BuildContext context) {
return Scaffold (body: MyText());
class MyText extends StatelessWidget {
Build widget (BuildContext context) {
return Container (child:
Center (child: Text ('Pablo')),
);
}
}
Note: This was done for example purposes only, you must componentize reusable, or componentizable widgets, to avoid the effect:
aa
aaa
aaaa
aaaaa
aaaaaa
aaaaaaa
aaaaaaa
But if you have a few lines of code you don't have to worry about it as much.

Flutter Provider, using child widget to update a list

I'm new to using Flutter and I am currently struggling to understand how to use the Provider package for the following task, or if it is even the correct implementation in the first place.
I have a widget that uses another widget within itself to update a time value.
In the parent widget I have the following:
class _AddTimesScreenState extends State<AddTimesScreen> {
List<TimeOfDay> times = [];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Provider<List<TimeOfDay>>.value(
value: times,
child: SetTimes()
In the 2nd widget, which is used to update the times list by using a time picker I have:
class _SetTimesState extends State<SetTimes> {
#override
Widget build(BuildContext context) {
final times = Provider.of<List<TimeOfDay>>(context);
Essentially my goal is to be able to update the times list in the 2nd widget so it can then be used in the first widget. I have methods to add TimeOfDay objects to the list, but when the code is run the list in the first widget does not appear to be updated.
Am I using Provider in a way that it's intended, or have I completely misunderstood its application?
Thanks
In the TimeOfDay class make sure you are extending it with Change Notifier.
How does provider know it has to rebuild?
When the class (TimeOfDay in your case) extends ChangeNotifier, you are provided with a method called notifylisteners() , this triggers a rebuild to all the widgets consuming the provider. So you should call this in the function that is changing the objects data in your class TimeOfDay.
So make sure you are:
extending ChangeNotifier in your class/model.
calling notifylisteners when data is changed.
Example :
class MyClass extends ChangeNotifier{
int a = 0;
addSomething(){
//Here we are changing data
a = a + 1;
notifylisteners();
}
}
let me know if this solves your error.

Trying to access state from widget, probably using wrong design

I'm learning flutter and trying to make a kind of MutableImage widget. The idea is to make a MutableImage StatefulWidget that would rebuild when a new image is provided. I try to avoid rebuilding the whole widget tree each time the image is changed because that seems overkill, and I plan to update the image several times per second. So I want to rebuild only that MutableImage widget.
So here is the code I have, with comments to explain where I'm stuck :
class MutableImage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return MutableImageState();
}
void updateImage(List<int> bytes) {
// !!!!!! Would like to call this method here, but state is not available from Widget, which means I want to do something wrong, but not sure exactly how I should do it...
// this.state.updateImage(bytes);
}
}
class MutableImageState extends State<MutableImage> {
List<int> _bytes;
void updateImage(List<int> bytes) {
setState(() {
_bytes=bytes;
});
}
#override
Widget build(BuildContext context) {
if ((_bytes==null)||(_bytes.length==0)) {
return Center(child: CircularProgressIndicator());
}
return Image.memory(_bytes);
}
}
Then the idea was to use this widget like this for example in another stateful widget
MutableImage _mutableImage;
#override
Widget build(BuildContext context) {
if (_mutableImage == null) _mutableImage=MutableImage();
return : Row( //using Row as an example, the idea is that the mutable Image is deep into a tree of widgets, and I want to rebuild only _mutableImage when image changes, not all widgets.
children : <Widget>[
child0, child1, _mutableImage, child3, child4
]
);
}
void updateImage(List<int> bytes) {
_mutableImage?.updateImage(bytes);
}
So is there a good way to do this ? I'm quite confused, thx for any help/hint.
This is a place for an application of a GlobalKey. In the parent Widget of MutableImage make a global key and pass that to MutableImage. With that key you can access MutableImage state by using .currentState on the key and calling updateImage.
You'll have to add key as an argument of the MutableImage constructor and call super(key: key). updateImage should also be moved the the state of MutableImage.
Key:
final GlobalKey<MutableImageState> _imageKey = GlobalKey<MutableImageState>();
Pass the key:
MutableImage(key: _imageKey);
Access the state:
_imageKey.currentState.updateImage();