Passing Data Between Screens
In React Router you pass data forward through URL params, route state (navigate('/detail', { state: item })), or query strings. You pass data back by lifting state up and passing a callback as a prop, or by using a global store. Flutter has a more explicit mechanism for both directions: pass data forward via widget constructor arguments (the same way you pass props), and pass data back by await-ing the Navigator.push future, which resolves to whatever value the next screen passes to Navigator.pop.
Side-by-side comparison
Section titled “Side-by-side comparison”// React — pass forward via route state// navigate('/detail', { state: { product } })
function ProductDetail() { const { state } = useLocation(); const { product } = state; return <h1>{product.name}</h1>;}
// Pass back via callback propfunction EditScreen({ onSave }) { return ( <button onClick={() => onSave({ name: 'Updated' })}> Save </button> );}// Flutter — pass forward via constructorclass ProductDetail extends StatelessWidget { final Product product; const ProductDetail({super.key, required this.product});
@override Widget build(BuildContext context) { return Text(product.name); }}
// Push with data:Navigator.push( context, MaterialPageRoute( builder: (_) => ProductDetail(product: item), ),);
// Pass back via pop return value:final result = await Navigator.push<Map<String, String>>( context, MaterialPageRoute(builder: (_) => const EditScreen()),);// result == { 'name': 'Updated' }
// In EditScreen:Navigator.pop(context, {'name': 'Updated'});Runnable example
Section titled “Runnable example”import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: ContactListScreen());
}
}
class Contact {
final String name;
final String email;
const Contact({required this.name, required this.email});
}
const contacts = [
Contact(name: 'Alice', email: '[email protected]'),
Contact(name: 'Bob', email: '[email protected]'),
Contact(name: 'Carol', email: '[email protected]'),
];
class ContactListScreen extends StatelessWidget {
const ContactListScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Contacts')),
body: ListView.builder(
itemCount: contacts.length,
itemBuilder: (context, index) {
final contact = contacts[index];
return ListTile(
title: Text(contact.name),
subtitle: Text(contact.email),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => ContactDetailScreen(contact: contact),
),
);
},
);
},
),
);
}
}
class ContactDetailScreen extends StatelessWidget {
final Contact contact;
const ContactDetailScreen({super.key, required this.contact});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(contact.name)),
body: Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Name: ${contact.name}',
style: const TextStyle(fontSize: 18)),
const SizedBox(height: 8),
Text('Email: ${contact.email}',
style: const TextStyle(fontSize: 18)),
],
),
),
);
}
}