Skip to content

Rendering Control

In Flutter, efficient rendering control is essential for crafting high-performance, responsive, and scalable applications. Reactter provides a way to easily control the rendering of components in the widget tree behavior effortlessly, using the flutter_reactter package. This package provides a collection of Widgets and some BuildContext methods:

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 ReactterProvider widget, which stores dependencies using the dependency injection system. This allows descendant widgets to access these dependencies as needed.
  • BuildContext Methods: These methods facilitate dependency access and rendering control within the widget tree. Reactter widgets like ReactterConsumer , ReactterSelector , and ReactterComponent 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
// Provides the `CounterController` dependency to the widget tree
11
return ReactterProvider<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
// Observes the `count` property of the `counterController`
23
// and rebuilds the widget tree when the `count` value changes
24
ReactterConsumer<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 will see a counter app with two buttons to increment and decrement the count value.

In this scenario, only the Text widget will be rebuilt when the count value changes, not the entire CounterView widget. This is because the ReactterConsumer widget observes the count property and triggers the rebuilding of the widget tree when the count value changes.

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

Here’s how we can refactor the code to use the watch method along with a Builder widget to achieve the same outcome:

counter_view.dart
23
// Observes the `count` property of the `counterController`
24
// and rebuilds the widget tree when the `count` value changes
25
ReactterConsumer<CounterController>(
26
listenStates: (counterController) => [counterController.count],
27
builder: (context, counterController, child) {
28
Builder(
29
builder: (context) {
30
// Observes the `count` property of the `counterController`
31
// and rebuilds 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 ReactterProvider 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. By embracing these strategies, you can optimize the performance and efficiency of your Flutter applications while ensuring a seamless user experience.