Un constructor fromJson
Parte de la sección Datos y red del Journey de Flutter de Coddy. Lección 17 de 27.
Leer user['name'] as String por todas partes en las pantallas se vuelve engorroso, y un solo error tipográfico en una clave lo rompe. La solución habitual es crear una clase para los datos, con un constructor que conoce el JSON. Se llama 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 es un constructor con nombre, una segunda forma de crear un User. La palabra factory permite que un constructor ejecute código y return el objeto que crea. Un constructor común no puede return nada.
Ahora el JSON se lee en un solo lugar. El resto de la aplicación obtiene un User real, donde user.name es un String y un error tipográfico provoca un error de compilación en lugar de un null:
final body = await fetch('/user');
return User.fromJson(jsonDecode(body));Casi todas las aplicaciones que se comunican con un servidor tienen un fromJson para cada tipo de datos que reciben.
Desafío
DifícilEl perfil indica Unknown: loadUser ignora el JSON. Añade a User una factory User.fromJson(Map<String, dynamic> json) que lea name, email y age, y haz que loadUser devuelva User.fromJson(jsonDecode(body)). Importa dart:convert.
Pruébalo tú mismo
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;
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Datos y red
Practica por tu cuenta: Compilador de Flutter online