createModel<T> function
- T factory(), {
- SignalModelOptions options = const SignalModelOptions(),
Creates a new model constructor with an instanced factory.
A SignalModel is a highly powerful architectural primitive designed to manage cohesive packages of related state, business logic, actions, and side effects.
Under the hood, SignalModel automatically tracks, scopes, and manages the lifecycle of any Effects
instantiated during its factory execution. When the model is disposed (by calling model.dispose()),
all nested/captured effects are clean up automatically, ensuring complete prevention of memory leaks.
Furthermore, if the factory returns a standard Dart Map, and wrapInAction is enabled (default),
all nested function properties are automatically wrapped in batched action transactions to optimize updates.
1. Advanced Architecture: Type-Safe Wrappers using Dart 3+ Extension Types
While dynamic subscript access model['increment']() is fast and flexible, it lacks static analysis safety.
To achieve compile-time type-safety, you can wrap the returned SignalModel in a standard Dart 3 extension type:
import 'package:signals/signals.dart';
// 1. Define the reactive model constructor
final counterModel = createModel(() {
final count = signal(0);
// Captured nested side-effect (e.g. logging or syncing to local storage)
effect(() {
print('Nested logger: count is ${count.value}');
});
return <String, dynamic>{
'count': count,
'increment': () => count.value++,
};
});
// 2. Create a premium, compile-safe extension type wrapper
extension type TypeSafeCounter(SignalModel<Map<String, dynamic>> _model) {
int get count => (_model['count'] as Signal<int>).value;
set count(int val) => (_model['count'] as Signal<int>).value = val;
void increment() => (_model['increment'] as Function)();
void dispose() => _model.dispose();
}
void main() {
// 3. Instantiate and wrap the model
final counter = TypeSafeCounter(counterModel());
// Now you have a beautifully autocomplete-friendly, compile-safe API!
print(counter.count); // Prints: 0 (and registers effect print: Nested logger: count is 0)
counter.increment(); // Prints: Nested logger: count is 1
// Dispose when done to clean up all captured nested effects
counter.dispose();
}
Implementation
SignalModelConstructor<T> createModel<T>(
T Function() factory, {
SignalModelOptions options = const SignalModelOptions(),
}) {
return SignalModelConstructor(factory, options: options);
}