In the ToDo tutorial of BlocLibrary I cam along the following snippet.
TodosOverviewState copyWith({
TodosOverviewStatus Function()? status,
List<Todo> Function()? todos,
TodosViewFilter Function()? filter,
Todo? Function()? lastDeletedTodo,
}) {
return TodosOverviewState(
status: status != null ? status() : this.status,
todos: todos != null ? todos() : this.todos,
filter: filter != null ? filter() : this.filter,
lastDeletedTodo:
lastDeletedTodo != null ? lastDeletedTodo() : this.lastDeletedTodo,
);
}
What does this exactly do, how does it work? I know the copyWith
but I don't get the .. Function()? ...
part.
I found one more reference with Google where it was stated that it helps overcoming a null
issue. But why do I need Function
and what happens otherwise?
========================
UPDATE: I am not asking what copyWith is good for, only why they are using Function()?
to copy a state
and a simpler construct to copy a data object. The tutorial can be found here. There you will find the Function
in the bloc code in "ToDosOverview" and the simpler one in the ToDoModel in "LocalStorageTodosApi"
CodePudding user response:
the copyWith(...) function is the only pattern used in Dart to copy an object. In Dart an object does not have a copy constructor as in C , you must do it with copyWith(...) . Moreover , in the view part , state objects cannot be modified, thus you cannot make a setter function, the only way to modify a state object is to copy it changing one/more items. Why this? Because the framework (flutter) must be awared when to repaint a Widget or not by changing the object (internally it uses a boolean isDirty
flag to decide if /not if to repaint the widget). How to aware it? if you 'hooked' an object to a View (Widget), how to aware that the object was changed ? you have two scenarios: one, you test the equivalence for every field in that object (in deeep), or : two, simply check if the new object is the same as before or not ( i.e.: the "pointer" was the same as before?). In that manner Flutter awares to repaint the Widget in significally less time. That's why objects that carry out data should all be "immutable" and why you will use the copyWith(...) everywhere to change them (and update the view). In fact freezed library is very useful because you will have your copyWith(...) without write it ( and many other features, like Unions, json serialize, etc...)
Why the fields are functions ?
Because in that manner you can set to null a field.
For example, if you want to copy TodosOverviewState
setting to null the status, with a "plain" implementation of the copyWith function you can not:
`TodosOverviewState` copyWith({
TodosOverviewStatus? status,
List<Todo> ? todos,
TodosViewFilter ? filter,
Todo? lastDeletedTodo,
}) {
return TodosOverviewState(
status: status != null ? status: this.status,
todos: todos != null ? todos : this.todos,
filter: filter != null ? filter : this.filter,
lastDeletedTodo:
lastDeletedTodo != null ? lastDeletedTodo : this.lastDeletedTodo,
);
}
In this "plain" implementation of the copyWith, if you make:
TodosOverviewState myObj = ... ;
var copied = myObj.copyWith(status : null );
You obtain that the copied
object is the same as myObj
.
But, with the functions, you will set status to null .