Table of contents
Basically, there are 3 types of callbacks in Dart/Flutter.
Void Callbacks: These callbacks do not return any value. They are used when we want to act without expecting any result in return.
Value Callbacks: These callbacks return a single value. They are used when we want to get a result from a function or an action.
Async Callbacks: These callbacks are used when we want to perform an action that takes some time to complete, such as fetching data from an API or reading data from a file. They return a Future object that can be used to retrieve the result once the action is complete.
Let's look at some examples of them
Void Callbacks:
This is simplest among 3.
We usually encounter it in ElevatedButton, Gestures, InkWell
Here is the simple declaration & calling syntax of it
// Declaration
final VoidCallback callback;
// Usage
callback: => print("Void Callback in action");
Value Callbacks:
Since the intention is to get some value out of callback, that's why accepts a parameter.
We usually encounter it in TextFields, TextForms
etc
// Declaration
final ValueChanged<String> onChange;
// Usage
onChange("some value");
Async Callbacks
This one is a bit complex among the 3
Since the intention is to get data/value asynchronously, some new keywords will play an important role such as Future
async
// Declaration
Future<Type> asyncCallback() async {
// Some async operation
...
}
// Usage
// To use it we have to use a special `Widget` knowns as `FutureBuilder` which will take this
FutureBuilder(
future: asyncCallback(),
builder: ...
);
Detailed example of Void Callbacks
void main() {
runApp(VoidCallbackTestWidget());
}
class VoidCallbackTestWidget extends StatefulWidget {
@override
_VoidCallbackTestWidget createState() => _VoidCallbackTestWidget();
}
class _VoidCallbackTestWidget extends State<VoidCallbackTestWidget> {
@override
Widget build(BuildContext context) {
return CallableWidget(
callback: () {
print("Void Callback in action");
},
);
}
}
class CallableWidget extends StatelessWidget {
final VoidCallback callback;
CallableWidget({required this.callback});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: callback,
child: const Text('Press me'),
);
}
}
Details example of Value Callbacks
void main() {
runApp(ValueCallbackTestWidget());
}
class ValueCallbackTestWidget extends StatefulWidget {
const ValueCallbackTestWidget({super.key});
@override
_ValueCallbackTestWidget createState() => _ValueCallbackTestWidget();
}
class _ValueCallbackTestWidget extends State<ValueCallbackTestWidget> {
@override
Widget build(BuildContext context) {
return CallableWidget(onChange: (changedValue) => print(changedValue));
}
}
class CallableWidget extends StatelessWidget {
final ValueChanged<String> onChange;
const CallableWidget({Key? key, required this.onChange}) : super(key: key);
@override
Widget build(BuildContext context) {
return TextField(
onChanged: (value) {
onChange(value);
},
decoration: const InputDecoration(
hintText: 'Enter some text...',
),
);
}
}
Detailed example of Async Callbacks
void main() {
runApp(AsyncCallbackTestWidget());
}
class AsyncCallbackTestWidget extends StatelessWidget {
Future<String> fetchData() async {
// Some async operation
await Future.delayed(Duration(seconds: 2));
return 'Data loaded successfully!';
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: fetchData(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!);
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return const CircularProgressIndicator();
}
},
);
}
}
Thanks for staying with me.
Hope the different callbacks concepts are now clear.
You can reach out to me via Linked In or https://nasirmomin.web.app