get_it_listenable_widget 0.1.0 copy "get_it_listenable_widget: ^0.1.0" to clipboard
get_it_listenable_widget: ^0.1.0 copied to clipboard

A ListenableWidget that resolves its ViewModel from GetIt, with optional factory params.

get_it_listenable_widget #

A ListenableWidget that resolves its ViewModel from GetIt, so you don't have to wire viewModelFactory by hand in every screen.

It removes this boilerplate:

class CounterPage extends ListenableWidget<CounterViewModel> {
  const CounterPage({super.key})
      : super(viewModelFactory: _resolve);

  static CounterViewModel _resolve(BuildContext _) =>
      GetIt.instance.get<CounterViewModel>();
  // ...
}

Install #

dependencies:
  get_it_listenable_widget: ^0.1.0

Importing this package re-exports listenable_widget, so ViewModel and friends come along for free:

import 'package:get_it_listenable_widget/get_it_listenable_widget.dart';

Usage #

The three type parameters mirror GetIt's factory shape: <VM, P1, P2> where P1 / P2 are the optional param1 / param2. Use void for unused slots.

No params #

class CounterPage extends GetItListenableWidget<CounterViewModel, void, void> {
  const CounterPage({super.key});

  @override
  Widget build(BuildContext context, CounterViewModel vm) =>
      Text('${vm.count}');
}

With factory params #

// Registration:
getIt.registerFactoryParam<CounterViewModel, int, void>(
  (initial, _) => CounterViewModel(initial),
);

// Widget:
class CounterPage extends GetItListenableWidget<CounterViewModel, int, void> {
  const CounterPage({required int initial, super.key})
      : super(param1: initial);

  @override
  Widget build(BuildContext context, CounterViewModel vm) =>
      Text('${vm.count}');
}

Inline, without a subclass #

GetItListenableWidgetBuilder<CounterViewModel, int, void>(
  param1: 10,
  builder: (context, vm) => Text('${vm.count}'),
)

Named instances / custom GetIt instance #

GetItListenableWidgetBuilder<CounterViewModel, void, void>(
  instanceName: 'secondary',
  getIt: myScopedGetIt,
  builder: (context, vm) => Text('${vm.count}'),
)

Lifecycle (autoDispose) #

autoDispose defaults to true — the widget disposes the ViewModel when it leaves the tree. That is correct for registerFactoryParam / registerFactory, where each lookup returns a fresh instance the widget owns.

When you resolve a shared instance (registerSingleton / registerLazySingleton), pass autoDispose: false so the widget never disposes an instance owned by GetIt:

class HomePage extends GetItListenableWidget<HomeViewModel, void, void> {
  const HomePage({super.key}) : super(autoDispose: false); // shared singleton

  @override
  Widget build(BuildContext context, HomeViewModel vm) => /* ... */;
}

ViewModel.context and shared instances (assignContext) #

ListenableWidget assigns its BuildContext to ViewModel.context on init. For a shared singleton resolved by several widgets, that would mean each widget overwrites the context the others set. To avoid this, assignContext defaults to autoDispose: a widget-owned factory instance gets its context assigned, a shared singleton (autoDispose: false) does not. Override it explicitly if you need the other behaviour:

// Single widget owns the instance but disposes it elsewhere — keep context:
super(autoDispose: false, assignContext: true);

Because of this, ViewModel.context is nullable — always null-check it before use (if (context case final ctx?) ...).

1
likes
160
points
23
downloads

Documentation

API reference

Publisher

verified publisherveenstra.dev

Weekly Downloads

A ListenableWidget that resolves its ViewModel from GetIt, with optional factory params.

Homepage
Repository (GitHub)
View/report issues

License

BSD-3-Clause (license)

Dependencies

flutter, get_it, listenable_widget

More

Packages that depend on get_it_listenable_widget