context_plus
This package combines context_ref and context_watch into a single, more convenient package.
Visit context-plus.sonerik.dev for more information and interactive examples.
Table of Contents
Features
- Provide any value to the descendant contexts with
Ref.bind(context, ...)
(or.bindLazy()
,.bindValue()
) - Fetch ancestor-provided value with
Ref.of(context)
- Make widget dependent on any observable value with
.watch(context)
(or.watchOnly()
) - Make widget dependent on any observable value provided via a
Ref
withRef.watch(context)
(orRef.watchOnly()
)
Supported observable types for Observable.watch()
and Ref<Observable>.watch()
:
Listenable
,ValueListenable
:ChangeNotifier
ValueNotifier
AnimationController
ScrollController
TabController
TextEditingController
FocusNode
PageController
RefreshController
- ... and any other
Listenable
derivatives
Future
,SynchronousFuture
Stream
ValueStream
(from rxdart)AsyncListenable
(from async_listenable)
3rd party supported observable types for Observable.watch()
via separate packages:
Bloc
,Cubit
(from bloc, using context_watch_bloc)Observable
(from mobx, using context_watch_mobx)Rx
(from get, using context_watch_getx)Signal
(from signals, using context_watch_signals)
Installation
- Add
context_plus
to yourpubspec.yaml
:flutter pub add context_plus
- Wrap your app in
ContextPlus.root
:ContextPlus.root( child: MaterialApp(...), );
- (Optional, but recommended) Wrap default error handlers with
ContextPlus.errorWidgetBuilder()
andContextPlus.onError()
to get better hot reload related error messages:void main() { ErrorWidget.builder = ContextPlus.errorWidgetBuilder(ErrorWidget.builder); FlutterError.onError = ContextPlus.onError(FlutterError.onError); }
- (Optional) Remove
context_ref
andcontext_watch
from yourpubspec.yaml
if you have them.
API
Ref
Ref<T>
is a reference to a value of type T
provided by a parent BuildContext
.
It behaves similarly to InheritedWidget
with a single value property and provides a conventional .of(context)
method to access the value in descendant widgets.
Ref<AnyObservableType>
also provides
.watch()
and .watchOnly()
methods to observe the value conveniently.
Ref
can be bound only to a single value per BuildContext
. Child contexts can override their parents' Ref
bindings.
Common places to declare Ref
instances are:
- As a global file-private variable.
final _value = Ref<ValueType>();
- Useful for sharing values across multiple closely-related widgets (e.g. per-screen values).
- As a global public variable
final appTheme = Ref<AppTheme>();
- Useful for sharing values across the entire app.
- As a static field in a widget class
class SomeWidget extends StatelessWidget { static final _value = Ref<ValueType>(); ... }
- Useful for adding a state to a stateless widget without converting it to a stateful widget. The same applies to all previous examples, but this one is more localized, which improves readability for such use-case.
Ref.bind()
T Ref<T>.bind(
BuildContext context,
T Function() create, {
void Function(T value)? dispose,
Object? key,
})
- Binds a
Ref<T>
to the value initializer (create
) for all descendants ofcontext
andcontext
itself. - Value initialization happens immediately. Use
.bindLazy()
if you need it lazy. - Value is
.dispose()
'd automatically when the widget is disposed. Provide adispose
callback to customize the disposal if needed. - Similarly to widgets,
key
parameter allows for updating the value initializer when needed.
Ref.bindLazy()
void Ref<T>.bindLazy(
BuildContext context,
T Function() create, {
void Function(T value)? dispose,
Object? key,
})
Same as Ref.bind()
, but the value is created only when it's first accessed via Ref.of(context)
or Ref.watch()
/Ref.watchOnly()
, thus not returned immediately.
Ref.bindValue()
T Ref<T>.bindValue(
BuildContext context,
T value,
)
- Binds a
Ref<T>
to thevalue
for all descendants ofcontext
andcontext
itself. - Whenever the value changes, the dependent widgets will be automatically rebuilt.
- Values provided this way are not disposed automatically.
Ref.of(context)
T Ref<T>.of(BuildContext context)
- Fetches the value of type
T
provided by theRef<T>.bind()
/Ref<T>.bindLazy()
/Ref<T>.bindValue()
in the nearest ancestor ofcontext
. - Rebuilds the widget whenever the value provided with
Ref<T>.bindValue()
changes. - Throws an exception if the value is not provided in the ancestor tree.
Ref<Observable>.watch()
and Observable.watch()
void Listenable.watch(BuildContext context)
void Ref<Listenable>.watch(BuildContext context)
- Rebuilds the widget whenever the
Listenable
notifies about changes.
T ValueListenable<T>.watch(BuildContext context)
T Ref<ValueListenable<T>>.watch(BuildContext context)
- Rebuilds the widget whenever the
ValueListenable
notifies about changes. - Returns the current value of the
ValueListenable
.
AsyncSnapshot<T> Future<T>.watch(BuildContext context)
AsyncSnapshot<T> Ref<Future<T>>.watch(BuildContext context)
AsyncSnapshot<T> Stream<T>.watch(BuildContext context)
AsyncSnapshot<T> Ref<Stream<T>>.watch(BuildContext context)
AsyncSnapshot<T> AsyncListenable<T>.watch(BuildContext context)
AsyncSnapshot<T> Ref<AsyncListenable<T>>.watch(BuildContext context)
- Rebuilds the widget whenever the value notifies about changes.
- Returns and
AsyncSnapshot
describing the current state of the value. .watch()
'ing aSynchronousFuture
orValueStream
(from rxdart) will return aAsyncSnapshot
with properly initializeddata
/error
field, if initial value/error exists.AsyncListenable
can be used for dynamic swapping of the listened-to async value without losing the current state. See the live search example for a practical use-case.
Many popular observable types from 3rd party packages have their own .watch()
methods provided by separate packages. See the 3rd party supported observable types for more information.
Ref<Observable>.watchOnly()
and Observable.watchOnly()
R TListenable.watchOnly<R>(
BuildContext context,
R Function(TListenable listenable) selector,
)
- Invokes
selector
whenever theTListenable
notifies about changes. - Rebuilds the widget whenever the
selector
returns a different value. - Returns the selected value.
R Future<T>.watchOnly<R>(
BuildContext context,
R Function(AsyncSnapshot<T> value) selector,
)
R Stream<T>.watchOnly<R>(
BuildContext context,
R Function(AsyncSnapshot<T> value) selector,
)
- Invokes
selector
whenever the async value notifies about changes. - Rebuilds the widget whenever the
selector
returns a different value. - Returns the selected value.