Un constructeur fromJson
Fait partie de la section Données et réseau du Journey Flutter de Coddy. Leçon 17 sur 27.
Lire user['name'] as String partout dans vos écrans devient vite compliqué, et une simple faute de frappe dans une clé suffit à tout casser. La solution habituelle consiste à créer une classe pour les données, avec un constructeur qui connaît le JSON. Il s’appelle fromJson :
class User {
User({required this.name, required this.age});
final String name;
final int age;
factory User.fromJson(Map<String, dynamic> json) {
return User(
name: json['name'] as String,
age: json['age'] as int,
);
}
}User.fromJson est un constructeur nommé, une deuxième façon de créer un User. Le mot factory permet à un constructeur d’exécuter du code et de return l’objet qu’il construit. Un constructeur ordinaire ne peut rien return.
Le JSON est maintenant lu à un seul endroit. Le reste de l’application obtient un véritable User, où user.name est une String et où une faute de frappe provoque une erreur de compilation plutôt qu’un null :
final body = await fetch('/user');
return User.fromJson(jsonDecode(body));Presque toutes les applications qui communiquent avec un serveur ont un fromJson pour chaque type de données reçu.
Défi
DifficileLe profil affiche Unknown : loadUser ignore le JSON. Ajoute à User une factory User.fromJson(Map<String, dynamic> json) qui lit name, email et age, et fais en sorte que loadUser renvoie User.fromJson(jsonDecode(body)). Importe dart:convert.
Essayez vous-même
import 'package:flutter/material.dart';
import 'api.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: ProfileScreen(),
);
}
}
class ProfileScreen extends StatefulWidget {
const ProfileScreen({super.key});
@override
State<ProfileScreen> createState() => _ProfileScreenState();
}
class _ProfileScreenState extends State<ProfileScreen> {
late Future<User> _user;
@override
void initState() {
super.initState();
_user = loadUser();
}
Future<User> loadUser() async {
final body = await fetch('/user');
print(body);
return User(name: 'Unknown', email: 'unknown', age: 0);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Profile')),
body: Center(
child: FutureBuilder<User>(
future: _user,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Could not load: ${snapshot.error}');
}
if (snapshot.hasData) {
final user = snapshot.data!;
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
user.name,
style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(user.email, style: const TextStyle(fontSize: 18)),
const SizedBox(height: 8),
Text('${user.age} years old'),
],
);
}
return const CircularProgressIndicator();
},
),
),
);
}
}
class User {
User({required this.name, required this.email, required this.age});
final String name;
final String email;
final int age;
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Données et réseau
1Futures
Une valeur qui arrive plus tardAttendre avec async et awaitFonctions qui renvoient des FuturesL’API d’entraînement de Coddy4JSON
Lire du JSONValeurs JSON et asUn constructeur fromJsonUne liste à partir de JSONChamps JSON manquantsEntraînez-vous par vous-même : Compilateur Flutter en ligne