useValueChanged
Watches a value and runs a callback whenever it changes (compared via ==), passing the previous value and the previous result. Returns the latest result, or null before the first change.
class ScrollDeltaText extends HookWidget {
final double scrollOffset;
const ScrollDeltaText({super.key, required this.scrollOffset});
Widget build(BuildContext context) {
// Recomputed only when scrollOffset changes; null on the first build.
final delta = useValueChanged<double, double>(
scrollOffset,
(oldOffset, _) => scrollOffset - oldOffset, // <- oldValue, oldResult
);
return Text('Moved ${delta ?? 0} px');
}
}
Signature
R? useValueChanged<T, R>(T value, R? Function(T oldValue, R? oldResult) valueChange);
value- the value to watch. The callback fires whenever it differs from the previous build's value.valueChange- receives the previousvalueand the previous result, and returns the new result.
The return value is the most recent result, or null until the first change occurs. The callback runs during the build phase, as part of comparing the old and new hook.
Use cases
- Computing something from the transition between two values (e.g. a scroll delta from the old and new offset)
- Reacting to a change in a single value without writing into a separate
useState - Threading state forward by feeding the previous result back into the next computation
Caveats
-
The callback does not run on the first build - only on subsequent builds where the value changed. Until then the hook returns
null, so the return type is always nullable. -
Comparison is by
==. A value whose==is broken (or an always-new instance) will either never fire or fire on every build. -
The callback runs during the build, so keep it a cheap, synchronous computation and do not call other hooks inside it. For side effects that react to a change, use
useEffectwith the value in its keys instead. -
To read the previous value without computing a transition, prefer
usePreviousValue/usePreviousIfNull(in the Misc category) - they are purpose-built and clearer than threading state throughuseValueChanged.
See also
- useEffect - run a side effect on change instead of computing a value
- useMemoized - cache a value computed from current state
- useState - own a value rather than deriving it from a transition