Skip to main content

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, including useProvided for states registered earlier.
  • alwaysNotifyDependents (true by default) - when true, dependents are notified on every refresh; set it to false to notify only when a state's value actually changes (via ==). Production apps usually pass false.
  • schedulerPriority - the Priority at which refreshes are scheduled. Defaults to Priority.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 useProvided only states registered above it; depending on one registered later throws.

    // DON'T
    const _providers = {
    SettingsState: useSettingsState, // <- Throws: depends on AuthState, registered below
    AuthState: 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 no BuildContext, so hooks that call useBuildContext won't work.

See also