useWithSelf
Builds a value that needs a stable reference to itself. The block receives a Value holding the very object it returns, so callbacks inside it can reach the finished result without a chicken-and-egg problem.
class StepperView extends HookWidget {
const StepperView({super.key});
Widget build(BuildContext context) {
final count = useState(0);
// The controller needs to call back into itself to reset.
final controller = useWithSelf<StepController>(
(self) => StepController(
increment: () => count.value++,
reset: () => self.value.increment(), // <- self.value is this StepController
),
);
return Column(
children: [
Text('${count.value}'),
TextButton(onPressed: controller.increment, child: const Text('+1')),
],
);
}
}
class StepController {
final void Function() increment;
final void Function() reset;
StepController({required this.increment, required this.reset});
}
Signature
T useWithSelf<T extends Object>(T Function(Value<T> self) block);
T useWithSelfOrNull<T>(T Function(Value<T?> self) block);
block- builds and returns the value. Theselfargument is aValuewhose.valueresolves to the objectblockreturns once construction finishes.- The block runs on every build, and
self.valueis reassigned to the latest result each time, so callbacks always see the current instance.
useWithSelf requires a non-nullable T and provides a Value<T>. useWithSelfOrNull allows a nullable result and provides a Value<T?> initialized to null - use it when the type isn't Object or when a null self is meaningful.
Use cases
- Building an object whose own methods or callbacks need to refer back to it (e.g. a controller that resets or re-emits itself)
- Wiring a callback that, by the time it runs, should operate on the fully-constructed value rather than a half-built one
Caveats
-
Do not read
self.valueduring construction (synchronously insideblock) - it is only assigned afterblockreturns. Reading it eagerly withuseWithSelfthrows (the holder is late-initialized); withuseWithSelfOrNullit yieldsnull. Read it only from callbacks that run later. -
useWithSelfconstrainsT extends Objectbecause its holder is a late, non-nullableValue. IfTcan benull, useuseWithSelfOrNull. -
The block runs on every build. Keep it cheap, and move any expensive one-off construction into a
useMemoizedinside the block.
See also
- useMemoized - the caching primitive behind this hook; use it for one-time construction
- useState - when the object does not need a self-reference
- useValueWrapper - the related pattern of a stable
Valueholder refreshed each build