HookProviderContainerWidget
Registers global states at the app root. It takes an ordered map of {StateType: useStateHook} and makes each result available to the subtree through useProvided, rebuilding dependents when a state changes.
// The ordered map of global states - each entry is registered under its own type.
const _providers = <Type, Object? Function()>{
AuthState: useAuthState,
SettingsState: useSettingsState, // <- May useProvided<AuthState>(): it is registered above
};
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return const HookProviderContainerWidget(
_providers,
alwaysNotifyDependents: false,
child: MaterialApp(home: Scaffold()),
);
}
}
Constructor
const HookProviderContainerWidget(
Map<Type, Object? Function()> providers, {
Key? key,
bool alwaysNotifyDependents = true,
Priority schedulerPriority = Priority.animation,
required Widget child,
});
providers(positional) - the ordered map from a state's type to the hook that builds it. Each hook runs in its own context, so it may call other hooks, includinguseProvidedfor states registered earlier.alwaysNotifyDependents(trueby default) - whentrue, dependents are notified on every refresh; set it tofalseto notify only when a state's value actually changes (via==). Production apps usually passfalse.schedulerPriority- thePriorityat which refreshes are scheduled. Defaults toPriority.animation.child- the subtree in which the registered states are available.
The BuildContext is registered automatically, so any state hook may call useBuildContext.
Use cases
- Registering app-wide states (auth, settings, current workspace) once, at the root above
MaterialApp - Building a hierarchy of global states where higher-level states depend on lower-level ones
The states a hook depends on:
class AuthState {
final bool isLoggedIn;
const AuthState({required this.isLoggedIn});
}
AuthState useAuthState() => const AuthState(isLoggedIn: false);
class SettingsState {
final ThemeMode themeMode;
const SettingsState({required this.themeMode});
}
SettingsState useSettingsState() {
// A higher-level state may depend on one registered before it.
final auth = useProvided<AuthState>();
return SettingsState(themeMode: auth.isLoggedIn ? ThemeMode.dark : ThemeMode.system);
}
Caveats
-
The map is an ordered dependency list, not an unordered bag. A state hook may
useProvidedonly states registered above it; depending on one registered later throws.// DON'Tconst _providers = {SettingsState: useSettingsState, // <- Throws: depends on AuthState, registered belowAuthState: useAuthState,}; -
Each entry is keyed by a
Type, and the value is resolved under that type. Registering two hooks under the same type is not meaningful - expose a distinct state type per entry, or derive a plain-value provider under the value's own type. -
A raw
HookProviderContainer(the object behind this widget) can be used without Flutter, e.g. in tests. In that mode there is noBuildContext, so hooks that calluseBuildContextwon't work.
See also
- useProvided - consumes the states registered here
- ProviderWidget -
ValueProvider, for providing static values lower in the tree - Global state - the wider pattern for app-wide state