Skip to content

Rendering control

In Flutter, efficient rendering control is crucial for building high-performance, responsive, and scalable applications. The flutter_reactter package offers a straightforward way to manage widget tree rendering behavior, enabling to optimize performance and fine-tune their app’s responsiveness with ease.

API

This package provides the following rendering control mechanisms:

How it works

The rendering control in Reactter is based on two core concepts of Flutter:

  • InheritedWidget: This powerful mechanism efficiently shares data across the widget tree. Reactter extends this capability with the RtProvider widget, which stores dependencies using the dependency injection system. This allows descendant widgets to access these dependencies as needed.
  • BuildContext Extensions: These methods facilitate dependency access and rendering control within the widget tree. Reactter widgets like RtConsumer , RtSelector , and RtComponent use these methods to observe dependencies or states. Whenever the dependency or any observed state undergoes a change, these widgets promptly trigger the rebuilding of the widget tree to reflect the updated state.

Example

Let’s create a simple counter app using Reactter to demonstrate how to control the rendering of the widget tree in Flutter.

1
import 'package:flutter/material.dart';
2
import 'package:flutter_reactter/flutter_reactter.dart';
3
import 'counter_controller.dart';
4
5
class Counter extends StatelessWidget {
6
const Counter({Key? key}) : super(key: key);
7
8
@override
9
Widget build(BuildContext context) {
10
// Provide the `CounterController` dependency to the widget tree
11
return RtProvider<CounterController>(
12
() => CounterController(),
13
builder: (context, counterController, child) {
14
return Row(
15
mainAxisSize: MainAxisSize.min,
16
children: [
17
ElevatedButton(
18
onPressed: counterController.decrement,
19
child: const Icon(Icons.remove),
20
),
21
const SizedBox(width: 8),
22
// Observe the `count` property of the `counterController`
23
// and rebuild the widget tree when the `count` value changes
24
RtConsumer<CounterController>(
25
listenStates: (counterController) => [counterController.count],
26
builder: (context, counterController, child) {
27
return Text("${counterController.count}");
28
},
29
),
30
const SizedBox(width: 8),
31
ElevatedButton(
32
onPressed: counterController.increment,
33
child: const Icon(Icons.add),
34
),
35
],
36
);
37
},
38
);
39
}
40
}
1
import 'package:reactter/reactter.dart';
2
3
class CounterController {
4
// Create a reactive state using the `Signal` class
5
final count = Signal(0);
6
7
void increment() {
8
count.value++;
9
}
10
11
void decrement() {
12
count.value--;
13
}
14
}
1
import 'package:flutter/material.dart';
2
import 'counter.dart';
3
4
class CounterView extends StatelessWidget {
5
const CounterView({Key? key}) : super(key: key);
6
7
@override
8
Widget build(BuildContext context) {
9
return Scaffold(
10
appBar: AppBar(
11
title: const Text("Counter"),
12
),
13
body: const Center(
14
child: Counter(),
15
),
16
);
17
}
18
}
1
import 'package:flutter/material.dart';
2
import 'counter_view.dart';
3
4
void main() {
5
runApp(MyApp());
6
}
7
8
class MyApp extends StatelessWidget {
9
@override
10
Widget build(BuildContext context) {
11
return MaterialApp(
12
home: CounterView(),
13
);
14
}
15
}

Now, when you run the app, you’ll see a counter application with two buttons to increment and decrement the count value.

In this scenario, only the Text widget will rebuild when the count value changes, while the CounterView widget will not rebuild entirely. This happens because the RtConsumer widget observes the count property and triggers a rebuild of the widget tree only when the count value changes.

In previous example, we used the RtConsumer widget to observe the count property of the counterController instance, but we can do the same functionality using the watch method of the BuildContext class.

Next, we’ll refactor the code to use the watch method along with the Builder widget to achieve the same result:

counter_view.dart
23
// Observe the `count` property of the `counterController`
24
// and rebuild the widget tree when the `count` value changes
25
RtConsumer<CounterController>(
26
listenStates: (counterController) => [counterController.count],
27
builder: (context, counterController, child) {
28
Builder(
29
builder: (context) {
30
// Observe the `count` property of the `counterController`
31
// and rebuild the widget tree when the `count` value changes
32
final counterController = context.watch<CounterController>(
33
(counterController) => [counterController.count],
34
);
35
36
return Text("${counterController.count}");
37
},
38
),

Although the watch method can be directly employed within the builder method of the RtProvider widget, it’s advisable to utilize it alongside a Builder widget to prevent unnecessary rebuilds of the widget tree. This practice leverages the BuildContext scope, offering a more granular approach to rendering control within the widget tree.

For more advanced use cases, you can employ other Reactter’s widgets and BuildContext methods to further refine the rendering control of the widget tree.