Skip to content

Instantly share code, notes, and snippets.

@josephdicdican
Last active March 31, 2022 21:40
Show Gist options
  • Save josephdicdican/81e59fad70530eac251ad6c28e2dcd4b to your computer and use it in GitHub Desktop.
Save josephdicdican/81e59fad70530eac251ad6c28e2dcd4b to your computer and use it in GitHub Desktop.
Flutter Navigate without Context with example
abstract class API {
// sample usage: API.get('/endpoint', {'get': 'request'})
static Future<dynamic> get(String endpoint, [Map<String, dynamic>? params]) async {
// NOTE: helper methods not included
var uri = API.parseEndpoint(endpoint);
var httpHeaders = await API.getHttpHeaders();
final response = await http.get(uri, headers: httpHeaders);
var data = jsonDecode(response.body);
if (response.statusCode == 200) {
return data;
} else {
// captures 401 response and redirect to login
API.throwFetchDataException(data, response);
}
}
static void throwFetchDataException(Map<String, dynamic> data, http.Response response) {
debugPrint('API exception statusCode: ${response.statusCode}');
if (response.statusCode == 401) {
debugPrint('API unauthorized exception captured, cleanup auth keys & redirect to login');
// AuthProvider().logout(); // delete expired auth keys
AppNavigatorService.pushNamed('/login'); // Solution to navigate without context
}
throw FetchDataException(data['message'] ?? 'Fetch exception');
}
}
// This is only to give rough overview of the structure of the fix.
// allow usage of navigator without context if the need arise
abstract class AppNavigatorService {
static final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
static Future<dynamic>? pushNamed(String routeName) {
debugPrint('route by navigatorKey: $routeName');
return AppNavigatorService.navigatorKey.currentState?.pushNamed(routeName);
}
static void pop() {
debugPrint('route by navigatorKey pop');
return AppNavigatorService.navigatorKey.currentState?.pop();
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CupertinoApp(
title: 'Navigate without Context',
initialRoute: '/',
navigatorKey: AppNavigatorService.navigatorKey,
onGenerateRoute: (settings) {
switch (settings.name) {
case '/login':
return CupertinoPageRoute(builder: (_) {
return Text('Login');
});
case '/':
default:
return CupertinoPageRoute(builder: (_) => MainPage());
}
},
);
}
}
class MainPage extends StatefulWidget {
MainPage({Key? key}) : super(key: key);
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
@override
void initState() {
super.initState();
callApi();
}
Future<void> callApi() async {
await API.get('/aunthenticated-route');
}
@override
Widget build(BuildContext context) {
return Container(child: Text('Main Page'));
}
}
@josephdicdican
Copy link
Author

This is a rough overview of the fix, imports not included. There are other ways to fix Navigate without context.

Quick fix is add using global navigatorKey

// main.dart
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); in main.dart

void main() {
  runApp(CupertinoApp(
    title: "Test",
    navigatorKey: navigatorKey,
  ));
}

// anywhere, use navigatorKey
navigatorKey.currentState?.pushNamed('/route-name');
navigatorKey.currentState?.pop();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment