I have a Flutter app that has a main localization provider, which is located at the root of my app. I then have a provider I want to provide only to the ‘registration’ route (which itself has a number of subroutes) since it handles all of the business logic and data associated with Registration. However, when I do this I get an error where I can’t use Provider.of because it says the provider was not provided by the context. What am I doing wrong? This seems like it should work from everything I have read. I have my code below, but I have omitted the all of the simple logic checks and such that are unrelated
The error occurs in registration_landing.dart on the line:
final registrationService = Provider.of<RegistrationService>(context, listen: false);
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// TBD:
// - Check if the user has already logged in to the app previously
const bool isRegistered = false;
runApp(
ChangeNotifierProvider(
create: (context) => LocaleProvider(),
child: const NextGen(isRegistered: isRegistered),
),
);
}
class NextGen extends StatelessWidget {
final bool isRegistered;
const NextGen({super.key, required this.isRegistered});
static FirebaseAnalytics analytics = FirebaseAnalytics.instance;
static FirebaseAnalyticsObserver observer = FirebaseAnalyticsObserver(analytics: analytics);
@override
Widget build(BuildContext context) {
final localeProvider = Provider.of<LocaleProvider>(context);
return MaterialApp(
title: 'Training',
key: const Key('homepage'),
theme: appTheme,
locale: localeProvider.locale,
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: localeProvider.locales,
navigatorObservers: <NavigatorObserver>[observer],
home: isRegistered ? const Dashboard() : const RegistrationLanding(),
routes: {
'registration': (context) => ChangeNotifierProvider(
create: (_) => RegistrationService(
registrationApi: RegistrationApi(),
),
child: const RegistrationNavigator(),
),
'dashboard': (context) => const Dashboard(),
'settings': (context) => const Settings(),
},
);
}
}
registration_navigator.dart:
class RegistrationNavigator extends StatelessWidget {
const RegistrationNavigator({super.key});
@override
Widget build(BuildContext context) {
return Navigator(
initialRoute: '/',
onGenerateRoute: (RouteSettings settings) {
WidgetBuilder builder;
switch (settings.name) {
case '/':
builder = (BuildContext context) => const RegistrationLanding();
break;
case '/personal_info':
builder = (BuildContext context) => const PersonalInfoPage();
break;
case '/success':
builder = (BuildContext context) => const RegistrationSuccess();
break;
default:
throw Exception('Invalid route: ${settings.name}');
}
return MaterialPageRoute(builder: builder, settings: settings);
},
);
}
}
registration_landing.dart
class RegistrationLanding extends StatefulWidget {
const RegistrationLanding({super.key});
@override
RegistrationLandingState createState() => RegistrationLandingState();
}
class RegistrationLandingState extends State<RegistrationLanding> {
Future<void> submitInformation(BuildContext context) async {
final registrationService = Provider.of<RegistrationService>(context, listen: false);
await registrationService.submitEmailAndDob(
context,
_emailController.text,
_dobController.text,
);
}
@override
void initState() {
super.initState();
// Setting up stuff
}
// Skipping over a number of methods
@override
Widget build(BuildContext context) {
return Builder(
builder: (context) {
return Scaffold(
key: const Key('registration-landing-page'),
body: Column(
children: [
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 80),
const Center(
child: Column(
children: [
SizedBox(height: 40),
TitleLarge('Welcome'),
],
),
),
const SizedBox(height: 20),
SingleLineTextEdit(
key: const Key('email'),
label: 'Email',
controller: _emailController,
validator: _isEmailInvalid,
),
const SizedBox(height: 20),
SingleLineTextEdit(
key: const Key('date-of-birth'),
label: 'Date of Birth',
controller: _dobController,
readOnly: true,
onTap: () => _selectDate(context),
),
const SizedBox(height: 5),
const InfoBlock('We will never sell your personal information.'),
const SizedBox(height: 15),
BasicDropdown<Country>(
label: 'Location',
key: const Key('location'),
items: _locations,
hint: 'Select a Location',
itemLabel: (value) => value.displayName,
selectedValue: _selectedLocation,
onChanged: (newValue) {
setState(() {
_selectedLocation = newValue;
_updateLocationValidation(newValue);
});
},
),
const SizedBox(height: 50),
],
),
),
),
StickyRoundedButton(
'Continue',
() {
GetIt.instance<HttpClient>().updateApiLocation(_selectedLocation!);
submitInformation(context);
},
width: 203,
height: 54,
enabled: _isFormValid,
),
],
),
);
},
);
}
}
Thanks a ton for any help!