I’m having issue with Flutter constructor. I’m coming form javascript background and I am confused why Dart is this much hard to code.
first let me tell how it would look like in ts/js
import {availableMeals} from "MealService";
type MealFilter={isGlutenFree:boolean};
type Meal=unknown; //just for brevity
class GridPage{
_filteredMeal: Meal[]
constructor(public filter?: MealFilter ){
this._filteredMeal= availableMeals.filter(x=> {
if (filter==null){
return true;
}
if(filter.isGlutenFree && !x.isGlutenFree){
return false;
}
return true;
});
// and alot of other calculations
}
}
I’m trying to convert the same thing to a flutter widget and I’m failing
my first try was to write something like this
class GridPage extends StatelessWidget {
const GridPage({super.key, this.filter = const []}){
filteredFoods = availableMeals.where((meal) {
if (filter == null) {
return true;
}
return false;
}).toList();;
}
final List<FilterModel>? filter;
final List<Meal> filteredFoods
}
i’m getting error
Const constructors can’t have a body.
Try removing either the ‘const’ keyword or the body.
if I remove the const
then I get error
‘filteredFoods’ can’t be used as a setter because it’s final.
Try finding a different setter, or making ‘filteredFoods’ non-final.
if I remove the final
from constructor then I get this error:
This class (or a class that this class inherits from) is marked as ‘@immutable’, but one or more of its instance fields aren’t final: GridPage.filteredFoods
so I tried to find a way to keep the final
and const
class GridPage extends StatelessWidget {
const GridPage({super.key, this.filter = const []});
final List<FilterModel>? filter;
final List<Meal> filteredFoods= availableMeals.where((meal) {
if (filter == null) {
return true;
}
return false;
}).toList();;
}
now I’m getting error that
The instance member ‘filter’ can’t be accessed in an initializer.
Try replacing the reference to the instance member with a different expression
so reluctantly I turned to colon syntax, to be frank I don’t know how that could scale for big calculation that need to be done once only in the constructor
class GridPage extends StatelessWidget {
const GridPage({super.key, this.filter = const []})
: filteredFoods= availableMeals.where((meal) {
if (filter == null) {
return true;
}
return false;
}).toList();
final List<FilterModel>? filter;
final List<Meal> filteredFoods;
}
I tried to wrap the assignment into a function since there are many of them
class GridPage extends StatelessWidget {
GridPage({super.key, this.filter = const []})
: init(filter);
getting error
Expected an assignment after the field name.
To initialize a field, use the syntax ‘name = value’
so now my question is how to handle if I have many calculation need to be done once in constructor time? also apparently can’t use anything with body (for, while, if).
I don’t want to switch to statefull just because of this.
I don’t like the idea of moving this to build
method too, why I have to calculate the list when filter haven’t changed yet?
is any way I can hold to stateless and do all calculations once?
2
Answers
Remove the
const
keyword from the constructor and addlate
modifier to thefilteredFoods
field. Usinglate
modifier on afinal
field allows you to assign value to the field later, but only once.More about the late final variables: https://dart.dev/null-safety/understanding-null-safety#late-final-variables
I would suggest you to do the calculation and other logic outside of constructor.
That would mean using stateful widget and doing calculations either in
initState()
or using aFutureBuilder
.If not, my suggestion is make filtered foods a
getter
instead of a final property.eg: