Scoping State

This page is a WIP, but you can create a new RearchConsumer in conjunction with a new InheritedWidget. You make a new RearchConsumer that manages some state (or takes in some data via its constructor) and then pass this state into a new InheritedWidget to provide said state to all descendants.

Something like the following macro is planned that will kill all of the RearchConsumer + InheritedWidget boilerplate:

@inheritedRearchWidget
(int, void Function()) scopedCount(WidgetHandle use) {
  final (count, setCount) = use.state(0);
  return (count, () => setCount(count + 1));
}

const SomeWidget(
  child: ScopedCount(
    child: Builder(
      builder: (context) {
	    final (count, _incrementCount) = ScopedCount.of(context);
		return Text('$count');
      },
    )
  ),
)

Here is a slightly different example, this time showing the generated boilerplate:

(int, void Function()) scopedCount(WidgetHandle use, int startingCount) {
  final (count, setCount) = use.state(startingCount);
  return (count, () => setCount(count + 1));
}

class ScopedCount extends RearchConsumer {
  const ScopedCount(this.startingCount, {required this.child, super.key});
  final int startingCount;
  final Widget child;

  @override
  Widget build(BuildContext context, WidgetHandle use) {
    return _ScopedCount(
      scopedCount(use, startingCount),
      child: child,
    );
  }

  static _ScopedCount? _maybeOf(BuildContext context) =>
      context.dependOnInheritedWidgetOfExactType<_ScopedCount>();

  static _ScopedCount _of(BuildContext context) {
    final widget = _maybeOf(context);
    assert(widget != null, 'No ScopedCount found in context');
    return widget!;
  }

  static (int, void Function())? maybeOf(BuildContext context) =>
      _maybeOf(context)?._data;

  static (int, void Function()) of(BuildContext context) => _of(context)._data;
}

class _ScopedCount extends InheritedWidget {
  const _ScopedCount(this._data, {required super.child});
  final (int, void Function()) _data;
  @override
  bool updateShouldNotify(_ScopedCount oldWidget) => oldWidget._data != _data;
}