55 order : 1
66---
77
8+ import { Aside } from ' @astrojs/starlight/components' ;
9+
810Helper library to make working with [ solidart] ( https://pub.dev/packages/solidart ) in [ flutter_hooks] ( https://pub.dev/packages/flutter_hooks ) easier.
911
1012``` dart
@@ -24,12 +26,16 @@ class Example extends HookWidget {
2426 });
2527 return Scaffold(
2628 body: Center(
27- child: Column(
28- mainAxisAlignment: MainAxisAlignment.center,
29- children: [
30- Text('Count: ${count.value}'),
31- Text('Double: ${doubleCount.value}'),
32- ],
29+ child: SignalBuilder(
30+ builder: (context, child) {
31+ return Column(
32+ mainAxisAlignment: MainAxisAlignment.center,
33+ children: [
34+ Text('Count: ${count.value}'),
35+ Text('Double: ${doubleCount.value}'),
36+ ],
37+ );
38+ }
3339 ),
3440 ),
3541 floatingActionButton: FloatingActionButton(
@@ -41,7 +47,66 @@ class Example extends HookWidget {
4147}
4248```
4349
44- ## useSignal
50+ <Aside type = " caution" >
51+ As you can see, a ` SignalBuilder ` is used to rebuild the widget when the signal changes.
52+ This is a good practice to avoid rebuilding the entire widget tree when a signal changes, and only rebuild the parts that depend on the signal.
53+ Alternatively, you can use ` useListenable ` from ` flutter_hooks ` to listen to the signal changes, but this will rebuild the entire widget tree; for example:
54+
55+ ``` dart
56+ class UseSignalExample extends HookWidget {
57+ const UseSignalExample({super.key});
58+
59+ @override
60+ Widget build(BuildContext context) {
61+ final count = useSignal(0);
62+ // this will rebuild the entire widget when the signal changes
63+ useListenable(count);
64+
65+ return Scaffold(
66+ appBar: AppBar(title: const Text('useSignal')),
67+ body: Center(child: Text('Count: ${count.value}')),
68+ floatingActionButton: FloatingActionButton(
69+ onPressed: () => count.value++,
70+ child: const Icon(Icons.add),
71+ ),
72+ );
73+ }
74+ }
75+ ```
76+
77+ There is another option which is to use ` HookBuilder ` + ` useListenable ` to only rebuild a part of the widget tree:
78+
79+ ``` dart {11-15}
80+ class UseSignalExample extends HookWidget {
81+ const UseSignalExample({super.key});
82+
83+ @override
84+ Widget build(BuildContext context) {
85+ final count = useSignal(0);
86+
87+ return Scaffold(
88+ appBar: AppBar(title: const Text('useSignal')),
89+ body: Center(
90+ child: HookBuilder(
91+ builder: (context) {
92+ useListenable(count);
93+ return Text('Count: ${count.value}');
94+ },
95+ ),
96+ ),
97+ floatingActionButton: FloatingActionButton(
98+ onPressed: () => count.value++,
99+ child: const Icon(Icons.add),
100+ ),
101+ );
102+ }
103+ }
104+ ```
105+
106+ But keep in mind that ` SignalBuilder ` is more optimized and will not trigger unnecessary rebuilds when multiple signals change at the same time.
107+ </Aside >
108+
109+ ## ** useSignal**
45110
46111How to create a new signal inside of a hook widget:
47112
@@ -51,7 +116,13 @@ class Example extends HookWidget {
51116 Widget build(BuildContext context) {
52117 final count = useSignal(0);
53118 return Scaffold(
54- body: Center(child: Text('Count: ${count.value}')),
119+ body: Center(
120+ child: SignalBuilder(
121+ builder: (context, child) {
122+ return Text('Count: ${count.value}');
123+ },
124+ ),
125+ ),
55126 floatingActionButton: FloatingActionButton(
56127 onPressed: () => count.value++,
57128 child: const Icon(Icons.add),
@@ -64,7 +135,7 @@ class Example extends HookWidget {
64135The widget will automatically rebuild when the value changes.
65136The signal will get disposed when the widget gets unmounted.
66137
67- ## useComputed
138+ ## ** useComputed**
68139
69140How to create a new computed signal inside of a hook widget:
70141
@@ -76,12 +147,16 @@ class Example extends HookWidget {
76147 final doubled = useComputed(() => count.value * 2);
77148 return Scaffold(
78149 body: Center(
79- child: Column(
80- mainAxisAlignment: MainAxisAlignment.center,
81- children: [
82- Text('Count: ${count.value}'),
83- Text('Doubled: ${doubled.value}'),
84- ],
150+ child: SignalBuilder(
151+ builder: (context, child) {
152+ return Column(
153+ mainAxisAlignment: MainAxisAlignment.center,
154+ children: [
155+ Text('Count: ${count.value}'),
156+ Text('Doubled: ${doubled.value}'),
157+ ],
158+ );
159+ },
85160 ),
86161 ),
87162 floatingActionButton: FloatingActionButton(
@@ -96,7 +171,7 @@ class Example extends HookWidget {
96171The widget will automatically rebuild when the value changes.
97172The computed will get disposed when the widget gets unmounted.
98173
99- ## useSolidartEffect
174+ ## ** useSolidartEffect**
100175
101176How to create a new effect inside of a hook widget:
102177
@@ -109,7 +184,13 @@ class Example extends HookWidget {
109184 debugPrint('Effect triggered! Count: ${count.value}');
110185 });
111186 return Scaffold(
112- body: Center(child: Text('Count: ${count.value}')),
187+ body: Center(
188+ child: SignalBuilder(
189+ builder: (context, child) {
190+ return Text('Count: ${count.value}');
191+ },
192+ ),
193+ ),
113194 floatingActionButton: FloatingActionButton(
114195 onPressed: () => count.value++,
115196 child: const Icon(Icons.add),
@@ -119,7 +200,7 @@ class Example extends HookWidget {
119200}
120201```
121202
122- ## useListSignal
203+ ## ** useListSignal**
123204
124205How to create a new list signal inside of a hook widget:
125206
@@ -129,7 +210,13 @@ class Example extends HookWidget {
129210 Widget build(BuildContext context) {
130211 final items = useListSignal<String>(['Item1', 'Item2']);
131212 return Scaffold(
132- body: Center(child: Text('Items: ${items.value.join(', ')}')),
213+ body: Center(
214+ child: SignalBuilder(
215+ builder: (context, child) {
216+ return Text('Items: ${items.value.join(', ')}');
217+ },
218+ ),
219+ ),
133220 floatingActionButton: FloatingActionButton(
134221 onPressed: () => items.add('Item${items.value.length + 1}'),
135222 child: const Icon(Icons.add),
@@ -142,7 +229,7 @@ class Example extends HookWidget {
142229The widget will automatically rebuild when the list changes.
143230The signal will get disposed when the widget gets unmounted.
144231
145- ## useSetSignal
232+ ## ** useSetSignal**
146233
147234How to create a new set signal inside of a hook widget:
148235
@@ -152,7 +239,13 @@ class Example extends HookWidget {
152239 Widget build(BuildContext context) {
153240 final uniqueItems = useSetSignal<String>({'Item1', 'Item2'});
154241 return Scaffold(
155- body: Center(child: Text('Items: ${uniqueItems.value.join(', ')}')),
242+ body: Center(
243+ child: SignalBuilder(
244+ builder: (context, child) {
245+ return Text('Items: ${uniqueItems.value.join(', ')}');
246+ },
247+ ),
248+ ),
156249 floatingActionButton: FloatingActionButton(
157250 onPressed: () => uniqueItems.add('Item${uniqueItems.value.length + 1}'),
158251 child: const Icon(Icons.add),
@@ -165,7 +258,7 @@ class Example extends HookWidget {
165258The widget will automatically rebuild when the set changes.
166259The signal will get disposed when the widget gets unmounted.
167260
168- ## useMapSignal
261+ ## ** useMapSignal**
169262
170263How to create a new map signal inside of a hook widget:
171264
@@ -176,8 +269,19 @@ class Example extends HookWidget {
176269 final userRoles = useMapSignal<String, String>({'admin': 'John'});
177270 return Scaffold(
178271 body: Center(
179- child: Text('Roles: ${userRoles.value.entries.map((e) => '${e.key}:${e.value}').join(', ')}'),
180- ),
272+ child: Column(
273+ mainAxisAlignment: MainAxisAlignment.center,
274+ children: [
275+ SignalBuilder(
276+ builder: (context, child) {
277+ return Text(
278+ 'Roles: ${userRoles.value.entries.map((e) => '${e.key}:${e.value}').join(', ')}',
279+ );
280+ },
281+ ),
282+ ],
283+ ),
284+ )
181285 floatingActionButton: FloatingActionButton(
182286 onPressed: () => userRoles['user${userRoles.value.length}'] = 'User${userRoles.value.length}',
183287 child: const Icon(Icons.add),
@@ -190,7 +294,7 @@ class Example extends HookWidget {
190294The widget will automatically rebuild when the map changes.
191295The signal will get disposed when the widget gets unmounted.
192296
193- ## useResource
297+ ## ** useResource**
194298
195299How to create a new resource inside of a hook widget:
196300
@@ -205,10 +309,14 @@ class Example extends HookWidget {
205309
206310 return Scaffold(
207311 body: Center(
208- child: userResource.state.on(
209- ready: (data) => Text('Result: $data'),
210- error: (error, stackTrace) => Text('Error: $error'),
211- loading: () => const CircularProgressIndicator(),
312+ child: SignalBuilder(
313+ builder: (context, child) {
314+ return userResource.state.on(
315+ ready: (data) => Text('Result: $data'),
316+ error: (error, stackTrace) => Text('Error: $error'),
317+ loading: () => const CircularProgressIndicator(),
318+ );
319+ },
212320 ),
213321 ),
214322 floatingActionButton: FloatingActionButton(
@@ -220,10 +328,9 @@ class Example extends HookWidget {
220328}
221329```
222330
223- The widget will automatically rebuild when the resource state changes.
224331The resource will get disposed when the widget gets unmounted.
225332
226- ## useResourceStream
333+ ## ** useResourceStream**
227334
228335How to create a new resource from a stream inside of a hook widget:
229336
@@ -237,10 +344,14 @@ class Example extends HookWidget {
237344
238345 return Scaffold(
239346 body: Center(
240- child: streamResource.state.on(
241- ready: (data) => Text('Stream value: $data'),
242- error: (error, stackTrace) => Text('Error: $error'),
243- loading: () => const CircularProgressIndicator(),
347+ child: SignalBuilder(
348+ builder: (context, child) {
349+ return streamResource.state.on(
350+ ready: (data) => Text('Stream value: $data'),
351+ error: (error, stackTrace) => Text('Error: $error'),
352+ loading: () => const CircularProgressIndicator(),
353+ );
354+ },
244355 ),
245356 ),
246357 floatingActionButton: FloatingActionButton(
@@ -252,10 +363,9 @@ class Example extends HookWidget {
252363}
253364```
254365
255- The widget will automatically rebuild when the resource state changes.
256366The resource will get disposed when the widget gets unmounted.
257367
258- ## useExistingSignal
368+ ## ** useExistingSignal**
259369
260370How to bind an existing signal inside of a hook widget:
261371
@@ -276,7 +386,13 @@ class _UseExistingSignalExampleState extends State<UseExistingSignalExample> {
276386 final boundSignal = useExistingSignal(existingSignal);
277387
278388 return Scaffold(
279- body: Center(child: Text('Value: ${boundSignal.value}')),
389+ body: Center(
390+ child: SignalBuilder(
391+ builder: (context, child) {
392+ return Text('Value: ${boundSignal.value}');
393+ },
394+ ),
395+ ),
280396 floatingActionButton: FloatingActionButton(
281397 onPressed: () => existingSignal.value++,
282398 child: const Icon(Icons.add),
@@ -292,5 +408,4 @@ class _UseExistingSignalExampleState extends State<UseExistingSignalExample> {
292408}
293409```
294410
295- The widget will automatically rebuild when the value changes.
296411The signal will NOT get disposed when the widget gets unmounted (unless autoDispose is true).
0 commit comments