Skip to content

UseEffect

UseEffect is a hook that allows to manage side-effect, and its functionality is closely related to Lifecycle of its dependencies or the bound instance.

Syntax

UseEffect(
void | Function callback(),
List<RtState> dependencies,
{ String? debugLabel },
);
// UseEffect run on init
UseEffect.runOnInit(
void | Function callback(),
List<RtState> dependencies,
{ String? debugLabel },
);

UseEffect accepts these parameters:

  • callback : A function that performs side effects. This function is executed when the dependencies trigger Lifecycle.didUpdate event or the bound instance trigger Lifecycle.didMount event. If the callback returns a Function (considers as an effect cleanup), it will be called before the next effect is run or the bound instance trigger Lifecycle.willUnmount event.

  • dependencies: A list of state( RtState , learn about it here) that the effect depends on.

  • debugLabel: (optional) A label to identify the hook in the DevTools extension.

Properties & Methods

UseEffect provides the following properties and methods:

Properties and methods inherited from RtState
  • debugLabel: A string that represents the label of the state object for debugging purposes.
  • debugInfo: A map that contains debug information about the state object.
  • update : Executes a callback function and notify its observers that the state has changed. When it is invoked, it emits two lifecycle events to signal the state transition:
    • Lifecycle.willUpdate is emitted first, indicating the impending update.
    • Lifecycle.didUpdate is emitted once the update process is complete.
  • notify : Forces the state to notify its observers. Unlike update , it emits only the Lifecycle.didUpdate event, as it doesn’t involve any preparatory steps before the notification.
  • bind : Establishes a connection between the state and a specific instance. This connection allows the instance to reactively update based on changes to the state. By binding the state, the instance becomes aware of changes to the state and can appropriately reflect those changes in its behavior.
  • unbind : Releases the connection between the state and the instance. When unbinding, the instance will no longer receive updates from the state. This can be useful when an instance is no longer actively using the state or when it needs to detach from the state temporarily or permanently.
  • dispose : Is responsible for cleaning up the state and any associated observers or resources. Disposing of the state ensures that it is properly released and no longer consumes memory or processing resources unnecessarily.

Usage

Declaration

UseEffect can be initialized using the constructor class, e.g.:

6 collapsed lines
1
class MyCounter {
2
final uCount = UseState(0);
3
4
const MyCounter() {
5
final timer = Timer.periodic(Duration(seconds: 1), (_) => uCount.value++);
6
7
UseEffect(() { // Effect callback
8
// Executed by `Lifecycle.didUpdate` event of `uCount` state
9
// or `Lifecycle.didMount` event of `MyCounter` instance
10
print("Count: ${uCount.value}");
11
12
return () { // Effect cleanup
13
// Executed by `Lifecycle.willUpdate` event of `uCount` state
14
// or `Lifecycle.willUnmount` event of `MyCounter` instance
15
if (uCount.value == 10 && timer.isActive) {
16
timer.cancel();
17
print("Counter stopped");
18
}
3 collapsed lines
19
};
20
}, [uCount]);
21
}
22
}

In the example above, the UseEffect hook is used to print the value of the uCount state every second and stop the timer when the value reaches 10 .

Running it inmediately

Sometimes you may want to execute the UseEffect immediately upon initialization. You can use UseEffect.runOnInit or the AutoDispatchEffect mixin to archive this. Here’s an example:

Using UseEffect.runOnInit

3 collapsed lines
1
final uCount = UseState(0);
2
3
void main() {
4
UseEffect.runOnInit(() { // Effect callback
5
// Executed at the initiation and by `Lifecycle.didUpdate` event of `uCount` state.
6
print("Count: ${uCount.value}");
7
Future.delayed(const Duration(seconds: 1), () => uCount.value++);
8
9
return () { // Effect cleanup
10
// Executed by `Lifecycle.willUpdate` event of `uCount` state.
11
print("Cleanup executed");
12
};
13
}, [uCount]);
1 collapsed line
14
}

In the example above, the UseEffect.runOnInit hook is used to print the value of the uCount state inmediately and increment the value every second.

Using AutoDispatchEffect mixin.

The AutoDispatchEffect mixin can be used to automatically execute the effect when the class is initialized. This is particularly useful when you want to ensure that the side effect runs as soon as the instance is created. Here’s an example:

3 collapsed lines
1
class MyCounter with AutoDispatchEffect {
2
final uCount = UseState(0);
3
4
MyCounter() {
5
final timer = Timer.periodic(Duration(seconds: 1), (_) => uCount.value++);
6
7
UseEffect(() { // Effect callback
8
// Executed by `Lifecycle.didUpdate` event of `uCount` state
9
// or `Lifecycle.didMount` event of `MyCounter` instance
10
print("Count: ${uCount.value}");
11
12
return () { // Effect cleanup
13
// Executed by `Lifecycle.willUpdate` event of `uCount` state
1 collapsed line
14
// or `Lifecycle.willUnmount` event of `MyCounter` instance
15
if (uCount.value == 10 && timer.isActive) {
16
timer.cancel();
17
print("Counter stopped");
18
}
19
};
20
}, [uCount]);
21
}
22
}

In this example, the AutoDispatchEffect mixin ensures that the UseEffect callback is executed immediately when the MyCounter instance is created. This eliminates the need to manually call UseEffect.runOnInit .